2008-10-30 16 views
7

me di cuenta de la specificaition para Collections.sort:¿Por qué SomeClass <? super T> no es equivalente a SomeClass <T> en tipos genéricos de Java?

public static <T> void sort(List<T> list, Comparator<? super T> c) 

¿Por qué es el "? super" necesario en este caso? Si ClassB se extiende ClassA, entonces ¿no tendríamos una garantía de que un Comparator<ClassA> sería capaz de comparar dos objetos ClassB de todos modos, sin la parte "? super"?

En otras palabras, dado este código:

List<ClassB> list = . . . ; 
Comparator<ClassA> comp = . . . ; 
Collections.sort(list, comp); 

por qué no es el compilador lo suficientemente inteligente para saber que esto está bien, incluso sin especificar "? super" para la declaración de Collections.sort()?

Respuesta

7

Josh Bloch tuvo una charla en Google I/O este año, llamada Effective Java Reloaded, que puede encontrar interesante. Habla de un mnemónico llamado "Pecs" (productor extends, consumidor super), lo que explica por qué usa ? extends T y ? super T en sus parámetros de entrada (solo; nunca para los tipos de devolución), y cuándo usarlos.

+0

Gracias, esta es una presentación útil. Creo que la raíz de mi problema es la primera diapositiva real: List no es una subclase de List , en la forma en que String [] es una subclase de Object []. – Kip

0

Es obvio que, en el caso de Comparator, cualquier ancestro de T funcionaría. Pero el compilador no sabe que la clase Comparator funciona de esa manera; solo necesita saber si debe permitir <T> o <? super T>.

Visto de otra manera, sí, es cierto que cualquier Comparator de un ancestro funcionaría en este caso, y la forma en que el desarrollador de la biblioteca dice que es usar <? super T>.

+0

pero no es obvio para mí - El comparador significa que tiene algunas funciones que solo funcionan en objetos de tipo T. Como todos los objetos de ClassB son también objetos de ClassA, todas las funciones del Comparador que solo funcionan en ClassA también funciona en ClassB. No se requiere conocimiento humano AFAIK – Kip

+0

@Kip: Nuevamente, vea que Josh Bloch hable para ver por qué los genéricos fueron _deliberadamente_ diseñados para que Foo _no_ se extienda desde Foo , incluso si Derived se extiende desde la Base. :-) –

1

Esto es similar a C#, me acabo de enterar hace un par de días de por qué (de la manera difícil, y luego la forma informativa de PDC).

Supongamos Dog extends Animal

Blah<Dog> es no lo mismo que Blah<Animal> tienen completamente diferentes firmas de tipos a pesar de que Dog extiende Animal.

Por ejemplo asumen un método en Blah<T>:

T Clone(); 

En Blah<Dog> esto es Dog Clone(); mientras que en Blah<Animal> esto es Animal Clone();.

usted necesita una manera de distinguir que el compilador puede decir que Blah<Dog> tiene la misma interfaz pública de Blah<Animal> y eso es lo que indica <? super T> - cualquier clase utilizados como T puede reducirse a su super clase en términos de Blah<? super T>.

(en C# 4.0 esto sería Blah<out T> creo.)

0

La respuesta simple a su pregunta es que el diseñador de la biblioteca quería dar la máxima flexibilidad al usuario de la biblioteca; esta firma de método, por ejemplo, le permite hacer algo como esto:

List<Integer> ints = Arrays.asList(1,2,3); 
Comparator<Number> numberComparator = ...; 

Collections.sort(ints, numberComparator); 

Usando el comodín le impide ser obligado a utilizar un Comparator<Integer>; el hecho de que el lenguaje requiere que el diseñador de la biblioteca especifique un comodín le permite a él o ella permitir o restringir dicho uso.

Cuestiones relacionadas