Допустим, у вас есть два класса, реализующих интерфейс: Foo
и Bar
Consumer<Bar> barConsumer = ...
Foo foo = new Foo();
foo.processRecursive(barConsumer);
Теперь, согласно сигнатуре метода, этот вызов processRecursive()
действителен, потому что barConsumer
подходит Consumer<? extends Recursive>
.
Однако код f.accept(this)
нарушит Consumer<Bar>
при попытке отправить объект Foo
в Comsumer
. Вот почему компилятор жалуется, потому что он не может гарантировать безопасность типов, то есть, что методу accept()
передаются только действительные объекты.
Поскольку нет способа обеспечить, чтобы this
был правильным подтипом Recursive
, нет типобезопасного способа сделать это.
Если вы в порядке с жертвой некоторого типобезопасности, вы можете сделать Recursive
generi c:
interface Recursive<T extends Recursive> {
List<T> getSubitems();
default void processRecursive(Consumer<T> consumer) {
consumer.accept((T) this); // sacrificing type-safety
for (T item : getSubitems())
consumer.accept(item);
}
}
Теперь его можно использовать как и все хорошо с миром:
class Foo implements Recursive<Foo> {
Но кто-то может написать это, взломав код, потому что теперь this
не является Bar
, поэтому приведение будет вызывать исключение во время выполнения (возможно, зависит от Java версии, которую я считаю) :
class Foo implements Recursive<Bar> {