useful parameter method example are java generics

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.