parameter - ¿Qué significa el signo de interrogación en el parámetro de tipo genéricos de Java?
java generics parameter (6)
El signo de interrogación se usa para definir comodines . Consulte la documentación de Oracle sobre ellos: http://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
Este es un pequeño fragmento de código tomado de algunos de los ejemplos que acompañan al analizador de Stanford. He estado desarrollando en Java durante aproximadamente 4 años, pero nunca he tenido una comprensión muy fuerte de lo que se supone que indica este estilo de código.
List<? extends HasWord> wordList = toke.tokenize();
No estoy preocupado por los detalles del código. Lo que me confunde es qué se supone que debe transmitir la expresión genérica, en inglés.
¿Alguien me puede explicar esto?
En inglés:
Es una
List
de algún tipo que extiende la claseHasWord
, incluyendoHasWord
En general, el ?
en genéricos significa cualquier clase. Y el extends SomeClass
especifica que ese objeto debe extender SomeClass
(o ser esa clase).
Tal vez un ejemplo artificial del "mundo real" ayudaría.
En el trabajo, tenemos contenedores de basura que vienen en diferentes sabores. Todos los contenedores contienen basura, pero algunos son especializados y no contienen todo tipo de basura. Entonces tenemos Bin<CupRubbish>
y Bin<RecylcableRubbsih>
. El sistema de tipo necesita asegurarse de que no puedo poner mi HalfEatenSandwichRubbish
en cualquiera de estos tipos, pero puede ir a un basurero general `` Bin . If I wanted to talk about a
. If I wanted to talk about a
Bin of
Rubbish which may be a specialist so I can''t put in incompatible rubbish, then that would be
Bin`.
(Nota: ? extends
" no significa "solo lectura." Por ejemplo, con las precauciones adecuadas puedo sacar un pedazo de basura de un contenedor de una especialidad desconocida y luego ponerlo en otro lugar).
No estoy seguro de cuánto ayuda eso. Puntero a puntero en presencia de polimorfismo no es del todo obvio.
Un signo de interrogación es un significante para ''cualquier tipo''. ?
solo significa
Cualquier tipo que se extienda
Object
(incluidoObject
)
mientras que su ejemplo anterior significa
Cualquier tipo de extensión o implementación de
HasWord
(incluyendoHasWord
siHasWord
es una clase no abstracta)
List<? extends HasWord>
List<? extends HasWord>
acepta cualquier clase concreta que amplíe HasWord. Si tienes las siguientes clases ...
public class A extends HasWord { .. }
public class B extends HasWord { .. }
public class C { .. }
public class D extends SomeOtherWord { .. }
... la lista de wordList
SÓLO puede contener una lista de As o Bs o una mezcla de ambos porque ambas clases extienden el mismo elemento primario o null
(que no HasWorld
instancia de verificación de HasWorld
).
? extends HasWord
significa "Una clase / interfaz que extiende HasWord
". En otras palabras, HasWord
o cualquiera de sus hijos ... básicamente cualquier cosa que funcione con instanceof HasWord
plus null
.
En términos más técnicos,? ? extends HasWord
es un comodín delimitado, cubierto en el Ítem 31 de Effective Java 3rd Edition , comenzando en la página 139. El mismo capítulo de la 2da Edición está disponible en línea como un PDF ; la parte de comodines delimitados es el Artículo 28 a partir de la página 134.
Actualización: el enlace PDF se actualizó desde que Oracle lo eliminó hace un tiempo. Ahora apunta a la copia organizada por la Escuela de Ingeniería Electrónica e Informática de la Universidad Queen Mary de Londres.
Actualización 2: veamos un poco más detalles sobre por qué querrías usar comodines.
Si declara un método cuya firma espera que pase en la List<HasWord>
, entonces lo único que puede pasar es una List<HasWord>
.
Sin embargo, si dicha firma fuera List<? extends HasWord>
List<? extends HasWord>
entonces usted podría pasar en su lugar una List<ChildOfHasWord>
.
Tenga en cuenta que hay una diferencia sutil entre List<? extends HasWord>
List<? extends HasWord>
y List<? super HasWord>
List<? super HasWord>
. Como lo expresó Joshua Bloch: PECS = producer-extends, consumer-super.
Lo que esto significa es que si está transfiriendo una colección de la que su método extrae datos (es decir, la colección está produciendo elementos para su método), debe usar extends
. Si está pasando una colección en la que su método agrega datos (es decir, la colección está consumiendo elementos que crea su método), debe usar super
.
Esto puede sonar confuso. Sin embargo, puede verlo en el comando de sort
List
(que es solo un acceso directo a la versión de dos arg de Collections.sort). En lugar de tomar un Comparator<T>
, realmente toma un Comparator<? super T>
Comparator<? super T>
. En este caso, el Comparador está consumiendo los elementos de la List
para reordenar la Lista misma.