Explicación del principio get-put

82

He leído el libro de O'Reilly, en el que llegué a conocer este principio de ponerse manos a la obra .

  • Utilice un extendscomodín cuando solo obtenga valores de una estructura.
  • Utilice un supercomodín cuando solo ponga valores en una estructura.
  • Y no use un comodín cuando ambos quieran obtener y poner desde / hacia una estructura.

Las excepciones son:

  • No puede poner nada en un tipo declarado con un extendscomodín excepto el valor null, que pertenece a cada tipo de referencia.

  • No puede obtener nada de un tipo declarado con un supercomodín, excepto un valor de tipo Object, que es un super tipo de cada tipo de referencia.

¿Alguien puede ayudarme a explorar esta regla en profundidad? Si es posible, colóquelos de manera jerárquica.

JavaResp
fuente
4
+1: Siempre es bueno ver a alguien buscar una aclaración sobre un fundamento
Todos
2
@Todo el mundo, supongo que se refiere a fundamento en el sentido fundamental en lugar del lado dorsal.
Rich Seller

Respuestas:

164

Considere un racimo de plátanos. Esto es Collection<? extends Fruit>porque es una colección de un tipo particular de fruta, pero no sabes (a partir de esa declaración) de qué tipo de fruta es una colección. Puede obtener un artículo y saber que definitivamente será una fruta, pero no puede agregarle ; es posible que esté tratando de agregar una manzana a un racimo de plátanos, lo que definitivamente estaría mal. Usted puede agregar nulla ella, como que será un valor válido para cualquier tipo de fruta.

Ahora considere un frutero. Esto es un Collection<? super Banana>, en el sentido de que es una colección de algún tipo "mayor que" Banana(por ejemplo, Collection<Fruit>o Collection<TropicalFruit>). Definitivamente puede agregar un plátano a esto, pero si saca un artículo del tazón, no sabe lo que obtendrá, es posible que no sea ​​un plátano. Todo lo que sabe con certeza es que será una referencia válida (posiblemente null) Object.

(En general, para las preguntas sobre genéricos de Java, las Preguntas frecuentes sobre genéricos de Java son un recurso excelente que contiene la respuesta a casi cualquier cosa relacionada con los genéricos que probablemente le arroje).

Jon Skeet
fuente
pero al buscar una fruta de la Colección <? extiende Frutas>, puede obtener cualquier fruta que no sea el plátano. de manera similar, mientras le pone una fruta, puede agregar cualquier cosa que no pertenezca a las frutas de plátano
JavaResp
6
Java evitará que agregue algo que no sea nulo a un Collection<? extends Fruit>exactamente por esa razón, y tendría que emitir explícitamente el resultado de obtener un elemento, precisamente por esas razones.
Jon Skeet
@JonSkeet Esta puede ser una pregunta estúpida, pero ¿en qué casos es útil no tener "acceso" a los métodos add () y get ()? Quiero decir, para sacar () algún objeto de una lista, primero tienes que agregarlo, ¿verdad? Y viceversa, ¿por qué lo agregarías si no puedes obtenerlo después?
Timmos
7
@Timmos: El hecho de que algo deba poder agregar un valor no significa que todo el código deba poder hacerlo. Por ejemplo, para mostrar una lista de nombres de personas, es posible que solo necesite un Collection<? extends Person>(o más probablemente solo un Iterable<? extends Person>, pero ...). El código que crea esa colección puede necesitar que sea un Collection<Employee>, pero el código consumidor no lo necesita .
Jon Skeet
5
@Timmos: Tendría que decir exactamente lo que quiso decir con "eso" en este caso ... pero sí, las reglas de los genéricos de Java están diseñadas para proporcionar seguridad de tipos.
Jon Skeet