J'ai rencontré cette classe dans le code que je gère:
new GenericFutureListener<Future<? super Void>>() {...}
J'ai beaucoup de mal à comprendre ce que cela signifie. Future
contenant un type qui est soit Void
, soit sa super-classe - Object
. Alors pourquoi ne pas écrire Future<Object>
?
On dirait que cela est créé pour se conformer à un type générique tel que GenericFutureListener<Future<? super T>>
, ce qui n’est pas assez souple pour autoriser GenericFutureListener<Future<Void>>
seul.
Par exemple, si vous avez quelque chose comme ça:
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
Passer uniquement un GenericFutureListener<Future<Void>>
n'est pas autorisé.
Quelque chose que personne d'autre n'a signalé: c'est Netty et si vous regardez https://netty.io/4.0/api/io/netty/util/concurrent/class-use/Future.html vous verrez qu'il y en a certaines méthodes ne prenant que ce type dans la bibliothèque, par exemple ChannelPromise.addListener(GenericFutureListener<? extends Future<? super Java.lang.Void>> listener)
. Et ces méthodes ont cette signature à cause du cas générique: Future.addListener(GenericFutureListener<? extends Future<? super V>> listener)
. ChannelPromise
étend simplement Future<Void>
.
Le cas générique a du sens car 1. si vous avez un FutureListener<Future<Object>>
, il peut gérer n’importe quelle valeur Object
lorsqu’un futur se termine; 2. Puisqu'un V
est un Object
il peut manipuler V
. Ainsi, il peut écouter un Future<V>
. Il en va évidemment de même pour tout supertype de V
au lieu de Object
.
Bien sûr, ces signatures seraient beaucoup plus simples si Java avait déclaration de site de déclaration , mais ce n'est pas et ne sera probablement pas bientôt.
Comme vous l'avez noté, ce Future<? super Void>
ne peut être qu'un futur vide ou un futur Object
.
Mais:
Alors pourquoi ne pas écrire Future?
L'intention du développeur était presque certainement de limiter les "auditeurs" à des actions nulles. Mais si on autorise Future<Object>
, alors tout autre type peut être utilisé comme valeur de la variable Future
, car un Future<Object>
peut contenir un résultat String
(ou tout autre type).
Java.lang.Void
étant une classe final
, elle n'autorise aucune classe enfant, ce qui la limite presque complètement aux actions void (à moins qu'une valeur pratique dans l'appel de new Object()
lors de la définition du résultat du futur)
Parfois, nous ne nous soucions que de la tâche accomplie ou non.
Quelqu'un (comme moi) peut préférer renvoyer Future<Void>
pour indiquer que la tâche n'a aucun résultat.
Tandis que quelqu'un d'autre préfère utiliser Future<Object>
ou Future<?>
et utiliser null
comme résultat.
Je pense que ce gars a rencontré à la fois Future<Void>
et Future<Object>
. Donc, il utilise Future<? super Void>
pour adapter les deux génériques.
Oui, vous pouvez utiliser un Future<Object>
avec cet écouteur, mais la déclaration indique clairement que l'écouteur devrait/n'utilise pas le résultat.
Déclarer ceci en tant que GenericFutureListener<Future<Object>>
donne l'impression que l'auditeur fait quelque chose avec le résultat.