Странная реализация tryAdvance в Spliterator.OfInt
Как это работает? Как может Consumer<? super Integer>
быть брошенным на IntConsumer
??
default boolean tryAdvance(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
return tryAdvance((IntConsumer) action);
}
else {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(),
"{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
return tryAdvance((IntConsumer) action::accept);
}
}
2 ответа
Ваш вопрос не совсем понятен, так как в размещенном коде есть два приведения типа.
Первый проверяет через instanceof
будь то Consumer<? super Integer>
также реализует IntConsumer
и затем выполняет приведение обычного типа, предполагая, что класс, реализующий Consumer
а также IntConsumer
в то же время будет делать это с той же семантикой. Сравните с документацией:
Требования к реализации:
Если действие является экземпляром
IntConsumer
тогда он приведен кIntConsumer
и перешел кtryAdvance(java.util.function.IntConsumer);
в противном случае действие адаптируется к экземпляруIntConsumer
, в боксе аргументIntConsumer
, а затем перешел кtryAdvance(java.util.function.IntConsumer)
,
Итак, первый instanceof
Проверка и приведение типа являются первой частью контракта, избегая бокса, если action
Аргумент реализует оба интерфейса.
Второй тип броска является частью описанной адаптации к боксу IntConsumer
в то время как бокс подразумевается ссылкой на метод (IntConsumer) action::accept
, Эта ссылка на метод относится к методу void accept(T t)
(где T := ? super Integer
) который может быть адаптирован к функции подписи IntConsumer
как описано Брайаном Гетцем. Поскольку эта функциональная подпись не только выполняет подпись IntConsumer
но также (конечно) подпись Consumer<? super Integer>
приведение типа необходимо для устранения неоднозначности между перегруженными tryAdvance
методы. Было бы ненужным при использовании эквивалентного лямбда-выражения
return tryAdvance((int i)->c.accept(i));
Приведение предоставляет целевой тип для привязанного метода action::accept
, что эквивалентно лямбде x -> action.accept(x)
, IntConsumer
Тип target вызывает адаптацию этой лямбды (которая предпочла бы принимать целое число) для принятия int (что приведет к неявному заключению аргумента в коробку перед передачей его в action.accept()
).