2010-10-16 12 views
6

Como un ejemplo práctico de la cuestión general en el tema, me gustaría poner en práctica el método containsAll en la interfaz Set conaplicación de interfaz con el argumento de un método superclases

public boolean containsAll(Iterable<?> c) { /* ... */ } 

Calculo esto se debe permitir, ya Collection es Iterable significando que containsAll cubriría el requisito de interfaz. Del mismo modo, en general, ser capaz de implementar interfaces con superclases de argumento parece que debería funcionar.

Sin embargo, Eclipse dice que no, de ninguna manera (no lo han intentado solo con javac): ¿alguien puede explicar el motivo? Estoy seguro de que hay algo en la especificación que lo hace tal como es, pero también me gustaría entender la motivación para los requisitos. ¿O me estoy perdiendo algo como Iterable<?> que no es una superclase de Collection<?>?

Como una pregunta complementaria: dado que declaro dos métodos, ¿el método con la firma Iterable siempre se preferirá en llamadas con un argumento Collection?

Eclipse error:

Si quito el método con la firma Collection, acaba de salir de la Iterable uno (ver después de un error), me sale el siguiente:

The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)

El ser exacta aplicación :

@Override public boolean containsAll(Collection<?> c) { 
    for (Object o : c) if (!contains(o)) return false; 
    return true; 
} 
public boolean containsAll(Iterable<?> c) { 
    for (Object o : c) if (!contains(o)) return false; 
    return true; 
} 
+0

¿Podría publicar un error que Eclipse le está dando? Funciona para mí en IDEA. –

+0

@Nikita: editado en. Tan ... ¿podría ser algo de Eclipse? – Carl

+0

Esta es una pesadilla de terminología. Me escapo de tales desafíos. – skaffman

Respuesta

2

Mi conjetura en cuanto a por qué Java tiene esta restricción es, supongamos que tiene:

class A { 
    void foo(String s) { ... } 
} 

class B extends A { 
    // Note generalized type 
    @Override void foo(Object s) { ... } 
} 

Ahora bien, si usted tiene class C extends B y quiere anular foo, no está claro qué argumento que debe tomar.

decir, por ejemplo C extendieron A directamente en un primer momento, anulando void foo(String s), y luego fue cambiado a extender B. En este caso existente aumento de C de foo llegaría a ser válida debido B de foo debe ser capaz de manejar todas las Object s, no solo String s.

+0

ah, parece ser una explicación sensata: ampliar la interfaz exigiría que las subclases mantengan la interfaz ampliada. Aún así, parece que debería permitirse, por lo general, las subclases no pueden restringir las interfaces. – Carl

+0

También probablemente haga que el diseño de la tabla virtual sea más claro al afirmar que todos los métodos tienen la firma exacta. O tal vez simplemente pensaron que podrían hacerlo funcionar si lo aclararon lo suficiente, pero no vieron una necesidad apremiante y la dejaron fuera. – oksayt

+0

Me falta algo, ¿se supone que ese ejemplo funciona? En la anotación @Override aparece "El método no anula el método de su superclase". – Amalgovinus

5

Dado que la interfaz que está implementando declara el (resumen) método containsAll(Collection<?>), debe implementarlo con esta firma exacta. Java no le permite implementar/anular un método con un tipo de parámetro más amplio que el original. Es por eso que aparece el error que muestra al comentar su método con la firma Collection.

No muestra el otro error que afirma tener cuando el método no está comentado, pero creo que podría tener que hacer algo con la sobrecarga de métodos ambigua.

+0

No hay ningún error cuando el método no está comentado. Solo cuando está el que tiene la firma 'Colección'. – Carl

+0

Además, ¿alguna idea de por qué este es el caso? ¿Es en la línea de la respuesta de @ oksayt? – Carl

+0

@Carl, ¿quieres decir por qué Java está diseñado así? Podría ser. –

0

Los tipos de argumentos son parte de la firma del método, por lo que jvm necesita un método con exactamente la misma firma para encontrar reemplazos. A containsAll (Iterable) tendrá una firma diferente a containsAll (Collection).

Si mal no recuerdo, el compilador tiene que usar algunas soluciones para hacer que los genéricos funcionen a pesar de esta limitación.

Para su segunda pregunta, el compilador preferiría el argumento Colección ya que es un subtipo de Iterable, esto hace que el método de Colección sea más específico que el Iterable.

Cuestiones relacionadas