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.