【问题标题】:Java Lambda function feeding with extend type带有扩展类型的 Java Lambda 函数
【发布时间】:2020-08-03 11:01:02
【问题描述】:

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 处理..

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

【问题讨论】:

  • 我可以,但是,如果我们说一个叶子对象扩展递归,其中包含一个叶子对象列表,我们将不得不将它们存储为 Recusive 列表并每次将它们转换为例如访问它的值使得使用它变得更加痛苦。因此,递归子类型的列表将更有用,据我所知,应该可以工作

标签: java recursion inheritance lambda extends


【解决方案1】:

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

Consumer<Bar> barConsumer = ...

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

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

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

由于无法强制 thisRecursive 的正确子类型,因此没有类型安全的方法来执行此操作。

如果您愿意牺牲一些类型安全,您可以将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> {

【讨论】:

  • 好吧,现在有道理了,有没有办法强制消费者扩展“this.getClass()”?
猜你喜欢
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-05
  • 2012-07-24
相关资源
最近更新 更多