Java 具有扩展类型的 Lambda 函数馈送

Java Lambda function feeding with extend type

Eclipse 告诉我:

interface Recursive
{
    List<? extends Recursive> getSubitems();

    default void processRecursive(Consumer<? extends Recursive> f)
    {
        f.accept(this);
        for (Recursive r : getSubitems())
            f.accept(r);
    }
}

不可能(f.accept(this) 和 f.accept(r) 错误:Consumer 类型中的方法 accept(capture#1-of ? extends Recursive) 不适用于参数(递归))

我想知道为什么,因为这将扩展 Recursive,所以 r(递归)也将扩展,并且它们可以作为 Recursives 处理..

在我看来,这是完全合理且可预测的行为。

假设您有两个 类 实现接口:FooBar

Consumer<Bar> barConsumer = ...

Foo foo = new Foo();
foo.processRecursive(barConsumer);

现在,根据方法签名,processRecursive() 调用是有效的,因为 barConsumer 适合 Consumer<? extends Recursive>

但是,代码 f.accept(this) 会尝试将 Foo 对象发送到 Comsumer,从而违反 Consumer<Bar>。这就是编译器抱怨的原因,因为它不能保证类型安全,即只向 accept() 方法提供有效对象。

由于无法强制 thisRecursive 的正确子类型,因此没有 type-safe 方法来做到这一点。

如果您可以牺牲 一些 类型安全,您可以将 Recursive 设为泛型:

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