java useful ¿Qué significa<? super vacío> significa?




java generics wildcard example (4)

Sí, puede usar un Future<Object> con ese Oyente, pero la declaración deja claro que el Oyente no debe usar el resultado.

Declarar esto como GenericFutureListener<Future<Object>> da la impresión de que el Oyente hace algo con el resultado.

Me he encontrado con esta clase de código que estoy manteniendo:

new GenericFutureListener<Future<? super Void>>() {...}

Me está costando mucho entender lo que esto significa. Un Future contiene un tipo que es Void o su superclase - Object . Entonces, ¿por qué no escribir Future<Object> ?


Algo que nadie más señaló: es Netty y si miras https://netty.io/4.0/api/io/netty/util/concurrent/class-use/Future.html verás que hay algunos métodos que solo toman este tipo en la biblioteca, por ejemplo, ChannelPromise.addListener(GenericFutureListener<? extends Future<? super java.lang.Void>> listener) . Y estos métodos tienen esta firma debido al caso genérico: Future.addListener(GenericFutureListener<? extends Future<? super V>> listener) . ChannelPromise simplemente extiende Future<Void> .

El caso genérico tiene sentido porque 1. si tiene un FutureListener<Future<Object>> , puede manejar cualquier valor de Object cuando se complete un futuro; 2. ya que una V es un Object que puede manejar V De esta forma puede escuchar un Future<V> . Obviamente, lo mismo se aplica a cualquier supertipo de V lugar de Object .

Por supuesto, estas firmas serían mucho más simples si Java tuviera una variación de sitio de declaración , pero no es así, y probablemente no lo hará pronto.


Como habrás notado, este Future<? super Void> Future<? super Void> solo puede ser un futuro vacío, o un futuro de Object .

Pero:

Entonces, ¿por qué no solo escribir el futuro?

La intención del desarrollador era casi seguro limitar a los "oyentes" a anular acciones. Pero si uno permitía Future<Object> , cualquier otro tipo podría usarse como valor del Future , porque un Future<Object> podría contener un resultado de String (o cualquier otro tipo).

java.lang.Void es una clase final , no permite ninguna clase secundaria, lo que prácticamente lo limita a acciones nulas (a menos que uno tenga un valor práctico en llamar a un new Object() al configurar el resultado del futuro)


Parece que esto se está creando para ajustarse a algún tipo genérico como GenericFutureListener<Future<? super T>> GenericFutureListener<Future<? super T>> , que no es lo suficientemente flexible como para permitir GenericFutureListener<Future<Void>> solo.

Por ejemplo, si tienes algo como esto:

class GenericFutureListener<T> {}

public static <T> void m(GenericFutureListener<Future<? super T>> p) {
    ...
}
m(new GenericFutureListener<Future<? super Void>>() {}); // works,
m(new GenericFutureListener<Future<Void>>() {}); // does not work

No se permite pasar solo un GenericFutureListener<Future<Void>> .





generics