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 de tipo del uso de tipos genéricos (parametrizados). [2] Se puede utilizar en declaraciones e instancias 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 las matrices (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 las conversiones (Generic<Subtype>)superGenericcomo para las (Generic<Supertype>)subGeneric.

Esta incompatibilidad se puede suavizar con el comodín if ?se utiliza como un 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 a Supertypey sus hijos. [5] Otra posibilidad es Generic<? super Subtype>, que también acepta ambos objetos y restringe la compatibilidad a Subtypey todos 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 el parámetro de tipo formal de un método, no se le pueden pasar parámetros reales. Sin embargo, los objetos del tipo desconocido se pueden leer desde el objeto genérico y asignar a una variable de un supertipo del límite superior.

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

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

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

... final Generic < UpperBound > concreteTypeReference = new Generic < UpperBound > (); final Generic <?> wildcardReference = concreteTypeReference ; final UpperBound ub = wildcardReference . read (); // El objeto también estaría bien wildcardReference . write ( new Object ()); // error de tipo wildcardReference . write ( new UpperBound ()); // error de tipo concreteTypeReference . write ( new UpperBound ()); // OK ...                    

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 una variable de tipo. 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 en realidad lo mismo que uno que tiene la restricción extends Object, ya que todos los tipos de referencia en Java son subtipos de Object.

Límites inferiores

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

Generic<? super SubtypeOfUpperBound> referenceConstrainedFromBelow;

puede contener cualquier parametrización Genericcuyo argumento de tipo sea tanto un subtipo del límite superior del parámetro de tipo correspondiente como un supertipo de SubtypeOfUpperBound. [5]

Creación de objetos con comodines

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 se encuentre dentro de las restricciones del comodín, si lo hubiera) como argumento de tipo.

Sin embargo, new ArrayList<Generic<?>>()se permite porque el comodín no es un parámetro del tipo instanciado ArrayList. Lo mismo se aplica a new ArrayList<List<?>>().

En una expresión de creación de matriz, el tipo de componente de la matriz debe ser verificable, tal como se define 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 ellos deben ser comodines ilimitados (comodines que constan únicamente de un ?). Por ejemplo, new Generic<?>[20]es correcto, mientras que new Generic<SomeType>[20]no lo es.

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

Ejemplo: Listas

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

public void doSomething ( List <? extends MyClass > list ) { for ( final MyClass object : list ) { // OK // haz algo } }                

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

public void doSomething ( List <? extends MyClass > list ) { final MyClass m = new MyClass (); list.add ( m ) ; // Error de compilación }              

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

public void doSomething ( Lista < ? super MiClase > lista ) { final MiClase m = nueva MiClase ( ); lista.add ( m ); // OK }              

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

public void doSomething ( List <? super MyClass > list ) { for ( final MyClass object : list ) { // Error de compilación // hacer algo } }                

Para poder hacer ambas cosas, agregar objetos de tipo MyClassa la lista e iterarla usando una variable de tipo MyClass, List<MyClass>se necesita a, que es el único tipo de Listque es a la vez y . [7]List<? extends MyClass>List<? super MyClass>

La mnemotecnia PECS (Producer Extends, Consumer Super) del libro Effective Java de Joshua Bloch proporciona una forma sencilla de recordar cuándo utilizar comodines (correspondientes a Covarianza y Contravarianza) en Java. [5]

Véase 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, pp. 117–122, Capítulo §5, Elemento 26: No utilice tipos sin procesar.
  3. ^ Gilad Bracha (junio de 2004), "4. Wildcards", 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", The Java Language Specification, Oracle , consultado el 6 de marzo de 2016
  5. ^ abcdef Bloch 2018, págs. 139–145, Capítulo §5, Elemento 31: Utilice comodines delimitados para aumentar la flexibilidad de la API.
  6. ^ Herencia (programación orientada a objetos)
  7. ^ Sintaxis de Java (Genéricos)

Referencias