stringtranslate.com

Comodín (Java)

En el lenguaje de programación Java , el comodín ? es un tipo especial de argumento de tipo [1] que controla la seguridad del uso de tipos genéricos (parametrizados). [2] Puede usarse en declaraciones e instanciaciones de variables, así como en definiciones de métodos, pero no en la definición de un tipo genérico. [3] [4] Esta es una forma de anotación de variación del sitio de uso , en contraste con las anotaciones de variación del sitio de definición que se encuentran en C# y Scala .

Covarianza para tipos genéricos

A diferencia de los arrays (que son covariantes en Java [2] ), las diferentes instancias de un tipo genérico no son compatibles entre sí, ni siquiera explícitamente. [2] Por ejemplo, las declaraciones Generic<Supertype> superGeneric; Generic<Subtype> subGeneric;harán que el compilador informe errores de conversión tanto para conversiones como para (Generic<Subtype>)superGenericarchivos (Generic<Supertype>)subGeneric.

Esta incompatibilidad puede suavizarse con el comodín si ?se utiliza como parámetro de tipo real. [2] Generic<?> es un supertipo de todas las parametrizaciones del tipo genérico Generic. Esto permite que los objetos de tipo Generic<Supertype>y Generic<Subtype>se asignen de forma segura a una variable o parámetro de método de tipo Generic<?>. [2] El uso Generic<? extends Supertype>permite lo mismo, restringiendo la compatibilidad con Supertypesus hijos. [5] Otra posibilidad es Generic<? super Subtype>, que también acepta ambos objetos y restringe la compatibilidad con Subtypetodos sus padres. [5]

Comodín como tipo de parámetro

En el cuerpo de una unidad genérica, el parámetro de tipo (formal) se maneja como su límite superior (expresado con extends; Objectsi no está restringido). [5] Si el tipo de retorno de un método es el parámetro de tipo, el resultado (por ejemplo, de tipo ?) puede ser referenciado por una variable del tipo del límite superior (o Object). En la otra dirección, el comodín no se ajusta a ningún otro tipo, ni siquiera Object: si ?se ha aplicado como parámetro de tipo formal de un método, no se le pueden pasar parámetros reales. Sin embargo, los objetos del tipo desconocido pueden leerse desde el objeto genérico y asignarse a una variable de un supertipo de límite superior.

Código de muestra para la clase:Generic<T extends UpperBound>

clase  Genérico < T extiende UpperBound > { privado T t ; escritura nula ( T t ) { esto . t = t ; } T leer () { devolver t ; } }                     

Código de muestra que utiliza la clase:Generic<T extends UpperBound>

... final Genérico < Límite Superior > concreteTypeReference = new Genérico < Límite Superior > (); final Genérico <?> referencia comodín = referencia de tipo concreto ; límite superior final ub = referencia comodín . leer (); // El objeto también estaría bien comodínReferencia . escribir ( nuevo objeto ()); // escribe error comodínReferencia . escribir ( nuevo límite superior ()); // tipo de error concreteTypeReference . escribir ( nuevo límite superior ()); // DE ACUERDO ...                    

Comodines acotados

Un comodín acotado es aquel que tiene una restricción de herencia superior o inferior . El límite de un comodín puede ser un tipo de clase, un tipo de interfaz , un tipo de matriz o un tipo de variable. Los límites superiores se expresan mediante la palabra clave extends y los límites inferiores mediante la palabra clave super . Los comodines pueden indicar un límite superior o un límite inferior, pero no ambos.

Límites superiores

Un límite superior en un comodín debe ser un subtipo del límite superior del parámetro de tipo correspondiente declarado en el tipo genérico correspondiente. [5] Un ejemplo de un comodín que establece explícitamente un límite superior es:

Generic<? extends SubtypeOfUpperBound> referenceConstrainedFromAbove;

Esta referencia puede contener cualquier parametrización Genericcuyo argumento de tipo sea un subtipo de SubtypeOfUpperBound. Un comodín que no indica explícitamente un límite superior es efectivamente lo mismo que uno que tiene la restricción extends Object, ya que todos los tipos de referencia en Java son subtipos de Objeto.

límites inferiores

Un comodín con un límite inferior, como por ejemplo

Generic<? super SubtypeOfUpperBound> referenceConstrainedFromBelow;

puede contener cualquier parametrización Genericcuyo argumento any type sea a la vez un subtipo del límite superior del parámetro de tipo correspondiente y un supertipo de SubtypeOfUpperBound. [5]

Creación de objetos con comodín.

No se pueden crear objetos con un argumento de tipo comodín: por ejemplo, new Generic<?>()está prohibido. En la práctica, esto es innecesario porque si uno quisiera crear un objeto que fuera asignable a una variable de tipo Generic<?>, simplemente podría usar cualquier tipo arbitrario (que esté dentro de las restricciones del comodín, si corresponde) como argumento de tipo.

Sin embargo, new ArrayList<Generic<?>>()está permitido porque el comodín no es un parámetro para el tipo instanciado ArrayList. Lo mismo vale para new ArrayList<List<?>>().

En una expresión de creación de matriz, el tipo de componente de la matriz debe ser verificable según lo definido en la Especificación del lenguaje Java, Sección 4.7. Esto implica que, si el tipo de componente de la matriz tiene algún argumento de tipo, todos deben ser comodines ilimitados (comodines que constan solo de un ?). Por ejemplo, new Generic<?>[20]es correcto, mientras que new Generic<SomeType>[20]no lo es.

En ambos casos, no utilizar parámetros es otra opción. Esto generará una advertencia ya que es menos seguro para los tipos (consulte Tipo sin formato ).

Ejemplo: listas

En Java Collections Framework, la clase List<MyClass>representa una colección ordenada de objetos de tipo MyClass. Los límites superiores se especifican usando extends: A es una lista de objetos de alguna subclase de , es decir, se garantiza que cualquier objeto en la lista es de tipo , por lo que se puede iterar sobre él usando una variable de tipo [6]List<? extends MyClass>MyClassMyClassMyClass

public void hacer algo ( Lista <? extiende MiClase > lista ) { para ( objeto final MiClase : lista ) { // OK // hacer algo } }                

Sin embargo, no se garantiza que se pueda agregar cualquier objeto de tipo MyClassa esa lista:

public void hacerAlgo ( Lista <? extiende MiClase > lista ) { final MiClase m = nueva MiClase (); lista . Agregame ) ;// Error de compilación }              

Lo contrario es cierto para los límites inferiores, que se especifican usando super: A es una lista de objetos de alguna superclase de , es decir, se garantiza que la lista podrá contener cualquier objeto de tipo , por lo que se puede agregar cualquier objeto de tipo :List<? super MyClass>MyClassMyClassMyClass

public void hacerAlgo ( Lista <? super MiClase > lista ) { final MiClase m = nueva MiClase (); lista . Agregame ) ;// DE ACUERDO }              

Sin embargo, no se garantiza que se pueda iterar sobre esa lista utilizando una variable de tipo MyClass:

public void hacer algo ( Lista <? super MiClase > lista ) { para ( objeto final MiClase : lista ) { // Error de compilación // hacer algo } }                

Para poder agregar objetos de tipo MyClassa la lista e iterar sobre ellos usando una variable de tipo MyClass, List<MyClass>se necesita a, que es el único tipo Listque es ambos y . [7]List<? extends MyClass>List<? super MyClass>

Los mnemotécnicos PECS (Producer Extends, Consumer Super) del libro Effective Java de Joshua Bloch brindan una manera fácil de recordar cuándo usar comodines (correspondientes a covarianza y contravarianza) en Java. [5]

Ver también

Citas

  1. ^ "Capítulo 4. Tipos, valores y variables". docs.oracle.com . Consultado el 3 de noviembre de 2020 .
  2. ^ abcde Bloch 2018, págs. 117–122, Capítulo §5 Artículo 26: No utilice tipos sin formato.
  3. ^ Gilad Bracha (junio de 2004), "4. Comodines", Genéricos en el lenguaje de programación Java (PDF) , consultado el 6 de marzo de 2016
  4. ^ "8.1.2 Clases genéricas y parámetros de tipo", La especificación del lenguaje Java, Oracle , consultado el 6 de marzo de 2016
  5. ^ abcdef Bloch 2018, págs. 139–145, Capítulo §5 Punto 31: Utilice comodines acotados para aumentar la flexibilidad de la API.
  6. ^ Herencia (programación orientada a objetos)
  7. ^ Sintaxis de Java (genéricos)

Referencias