method - java generics parameter
¿Qué significa<? super vacío> significa? (5)
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> ?
A veces solo nos importa la tarea que haya hecho o no.
Alguien (como yo) puede preferir devolver Future<Void> para indicar que la tarea no tiene ningún resultado.
Mientras que alguien más puede preferir usar Future<Object> o Future<?> Y usar null como resultado.
Creo que este tipo se encontró con Future<Void> y Future<Object> . ¿Entonces usa Future<? super Void> Future<? super Void> para adaptar ambos genéricos.
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>> .
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.