【问题标题】:Making a subclass to return itself without overriding使子类返回自身而不覆盖
【发布时间】:2020-11-13 15:24:50
【问题描述】:

假设我有一个接口Interface,它有一个方法aMethod(),它应该返回自己,但也有一个默认实现。然后我还有一个类Foo,它实现了Interface,并添加了额外的方法aFooMethod()

interface Interface {

    public default Interface aMethod() {
        // Some code
        return this;
    }
}

class Foo implements Interface {

    public void aFooMethod() {
        // Some code
    }
}

现在我无法调用new Foo().aMethod().aFooMethod();,因为aMethod() 返回一个Interface

现在我显然可以继续并覆盖 Foo 中的方法:

class Foo implements Interface {

    @Override
    public Foo aMethod() {
        Interface.super.aMethod();
        return this;
    }

    public void aFooMethod() {
        // Some code
    }
}

我的问题是,如果有一个好的方法来强制这样做,子类必须返回自己而不必重写该方法?

我最好的方法是这样说:

interface Interface<I extends Interface<I>> {

    @SupressWarnings("unchecked")
    public default I aMethod() {
        // Some code
        return (I)this;
    }
}

但这不是我认为的,因为它必须使用SupressWarnings("unchecked")。有没有更好的办法?

【问题讨论】:

  • 接口存在可能被多个子类子类化,有时在接口之后很长时间才创建。协变返回类型的便利性是这些子类的某些子集的实现细节。一种选择是让接口不了解子类的实现细节。
  • 在我的例子中,我正在创建一个 Vector 接口。然后我有两个子类,Vector2D 和 Vector3D。因为即使你实际上没有固定数量的维度,如果你有它的大小,你也可以轻松地缩放一个向量,所以我想使用默认方法来完成所有这些。但是,这些链式方法调用不适用于特定于类的方法,例如请求 z 坐标,因为该方法只会返回 Vector,而不是 Vector3D,并且没有 z getter。我不得不重写所有默认方法只是为了返回一个 Vector3D,这并不是拥有默认方法的真正意义。
  • 您是否考虑过实现接口的抽象类 AbstractVector,由 Vector2D 和 Vector3D 扩展,为具体子类提供一些受保护的缩放方法?例如,缩放一个大小取决于子类的数组?
  • 4d 向量呢? 5天? 42天?如果数学家掌握了你的代码,你会遇到麻烦
  • @Andy Thomas 问题是 Vector2D 和 Vector3D 也有一些他们不共享的方法,例如叉积(返回 3D 的 Vector,2D 的双精度)或旋转(显然可以'不只用一个角度表达 3D 旋转)所以另一个抽象类不会真正有意义,因为实际的类仍然必须使用覆盖返回自身

标签: java generics inheritance


【解决方案1】:

我最近问了一个关于同样事情的问题,但在 C# 中。但是,问题和答案仍然相同:这样的事情是不可能的。

你提到的模式

interface Interface<I extends Interface<I>> {}

一开始似乎是个不错的方法,但一旦有多个类实现了Interface,它就会崩溃。问题不是压制警告的必要性,它实际上是更大的东西。如果我这样创建两个类:

class A implements Interface<A> {}
class B implements Interface<A> {}

它仍然可以工作。约束I extends Interface&lt;I&gt; 只强制类型参数IInterface&lt;I&gt;,而A 确实实现了Interface&lt;A&gt;,因此即使Interface&lt;A&gt;B 实现,它也满足约束。

我一直在尝试解决这个问题,但遗憾的是,Java 和 C# 都不允许这样做。

【讨论】:

    猜你喜欢
    • 2017-03-20
    • 2019-08-26
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 2010-11-06
    • 1970-01-01
    相关资源
    最近更新 更多