Что значит <? super Void> имею в виду?
Я столкнулся с этим классом в коде, который я поддерживаю:
new GenericFutureListener<Future<? super Void>>() {...}
Мне очень трудно понять, что это значит. Future
содержащее тип, который является либо Void
либо его суперкласс - Object
. Так почему бы просто не написать Future<Object>
?
Ответы
Ответ 1
Похоже, что это создается для соответствия некоторому родовому типу, например GenericFutureListener<Future<? super T>>
GenericFutureListener<Future<? super T>>
, который не является достаточно гибким, чтобы позволить GenericFutureListener<Future<Void>>
самостоятельно.
Например, если у вас есть что-то вроде этого:
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
Передача только в GenericFutureListener<Future<Void>>
не допускается.
Ответ 2
Что-то, что никто другой не указал: это Netty, и если вы посмотрите на https://netty.io/4.0/api/io/netty/util/concurrent/class-use/Future.html, вы увидите, что есть некоторые методы, этот тип в библиотеке, например ChannelPromise.addListener(GenericFutureListener<? extends Future<? super java.lang.Void>> listener)
. И эти методы имеют эту подпись из-за общего случая: Future.addListener(GenericFutureListener<? extends Future<? super V>> listener)
. ChannelPromise
просто расширяет Future<Void>
.
Общий случай имеет смысл, потому что 1. если у вас есть FutureListener<Future<Object>>
, он может обрабатывать любое значение Object
при завершении будущего; 2. Поскольку V
является Object
он может обрабатывать V
Таким образом, он может слушать Future<V>
. Очевидно, что то же самое верно для любого супертипа V
вместо Object
.
Конечно, эти подписи были бы намного проще, если бы у Java была дисперсия объявления-сайта, но это не так и, вероятно, не скоро.
Ответ 3
Как вы уже отметили, это Future<? super Void>
Future<? super Void>
может быть только пустым будущим или Object
будущего.
Но:
Так почему бы просто не написать "Будущее"?
Намерение разработчика было почти наверняка ограничить "слушателей" пустым действием. Но если вы допустили Future<Object>
, тогда любой другой тип мог бы использоваться как значение Future
, потому что Future<Object>
мог содержать результат String
(или любой другой тип).
java.lang.Void
являющийся final
классом, не допускает каких-либо дочерних классов, которые фактически почти полностью ограничивают его действиями void (если у человека нет практического значения при вызове new Object()
при определении результата в будущем)
Ответ 4
Да, вы можете использовать Future<Object>
с этим прослушивателем, но в декларации ясно, что Listener должен/не использовать результат.
Объявление этого как GenericFutureListener<Future<Object>>
дает впечатление, что Listener делает что-то с результатом.
Ответ 5
Иногда мы заботимся только о том, что было сделано или нет.
Кто-то (как я) может предпочесть вернуть Future<Void>
чтобы указать, что задача не имеет результата.
В то время как кто-то другой предпочитает использовать Future<Object>
или Future<?>
И использовать null
в качестве результата.
Я думаю, что этот парень столкнулся с Future<Void>
и Future<Object>
. Итак, он использует Future<? super Void>
Future<? super Void>
чтобы адаптировать оба общих.