with multiple method interfaces genericas generic clases c# java generics generic-programming

c# - multiple - ¿Alguien puede explicar qué hace<? super T> mean y cuándo debería usarse y cómo debería cooperar esta construcción con<T> y<? extiende T>?



interfaces generics c# (4)

Estoy usando genéricos durante bastante tiempo, pero nunca he usado construcción como List<? super T> List<? super T> .

Qué significa eso? ¿Cómo usarlo? ¿Cómo se ve después del borrado?

También me pregunto: ¿es algo estándar en la programación genérica (programación de plantillas?) O es solo un ''invento'' de java? ¿C #, por ejemplo, permite construcciones similares?


Esta construcción se utiliza cuando desea consumir elementos de una colección en otra colección. Por ejemplo, tiene una Stack genérica y desea agregar un método popAll que tome una colección como parámetro y popAll en ella todos los elementos de la pila. Por sentido común, este código debe ser legal:

Stack<Number> numberStack = new Stack<Number>(); Collection<Object> objects = ... ; numberStack.popAll(objects);

pero se compila solo si define popAll como este:

// Wildcard type for parameter that serves as an E consumer public void popAll(Collection<? super E> dst) { while (!isEmpty()) dst.add(pop()); }

El otro lado de la moneda es que pushAll debería definirse así:

// Wildcard type for parameter that serves as an E producer public void pushAll(Iterable<? extends E> src) { for (E e : src) push(e); }

Actualización: Josh Bloch propaga este mnemónico para ayudarlo a recordar qué tipo de comodín usar:

PECS significa productor-extiende, consumidor-super .

Para más detalles, vea la 2da edición efectiva de Java, artículo 28 .


Estas cosas se conocen, en teoría de tipos, como varianza , con <? extends T> <? extends T> siendo una notación covariante, y <? super T> <? super T> ser una notación contra-variante. La explicación más simple es que ? puede ser reemplazado por cualquier tipo que extienda T en la notación covariante, y ? Puede ser reemplazado por cualquier tipo que T extienda en la contra-variante.

Usar co y contra-varianza es mucho más difícil de lo que parece al principio, particularmente porque la varianza "cambia" según la posición.

Un ejemplo simple sería una clase de función. Digamos que tienes una función que toma una A y devuelve una B La notación correcta sería decir que A es contra-variante y B os co-variante. Para comprender mejor cómo es este el caso, consideremos un método, llamémoslo g , que recibe esta clase de función hipotética, donde se supone que f recibe un Arc2D y devuelve una Shape .

Dentro de g , esta f se llama pasar un Arc2D y el valor de retorno se usa para inicializar un Area (que espera una Shape ).

Ahora, suponga que la f que pasa recibe cualquier Shape y devuelve un Rectangle2D . Dado que un Arc2D también es una Shape , entonces g no recibirá un error al pasar un Arc2D a f , y como un Rectangle2D también es una Shape , entonces se puede pasar al constructor del Area .

Si intenta invertir cualquiera de las variaciones o intercambiar los tipos reales y esperados en ese ejemplo, verá que falla. Ahora no tengo tiempo para escribir este código, y mi Java está bastante oxidado, por lo menos, pero veré qué puedo hacer después, si nadie es lo suficientemente amable como para hacerlo primero.


Esto se llama "comodín acotado". Está muy bien explicado en el tutorial oficial .

Como se indica en el tutorial, sabe que la lista contiene objetos de exactamente un subtipo de T

Por ejemplo, List<? extends Number> List<? extends Number> puede contener solo List<? extends Number> Integer o solo Long , pero no ambos.


Las preguntas frecuentes de Java Generics tienen una buena explicación sobre los genéricos de Java. Compruebe la pregunta ¿Qué es un comodín acotado? lo que explica el uso de la construcción "? super T" con buen detalle.