web-dev-qa-db-fra.com

Qu'est-ce que <? super vide> moyen?

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>?

23
jammaster

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é.

9
Jorn Vernee

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.

13
Alexey Romanov

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)

2
ernest_k

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.

0
Dean Xu

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.

0
kutschkem