Что значит <? 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> чтобы адаптировать оба общих.