7

我必须为分层实体设计一个接口:

interface HierarchicalEntity<T extends HierarchicalEntity<T>> {
    T getParent();
    Stream<T> getAncestors();
}

实现默认 getAncestors()方法很容易getParent(),因为前者将返回Stream所有祖先。

实现示例:

default Stream<T> getAncestors() {
    Stream.Builder<T> parentsBuilder = Stream.builder();
    T parent = getParent();
    while (parent != null) {
        parentsBuilder.add(parent);
        parent = parent.getParent();
    }
    return parentsBuilder.build();
}

但是我还需要包含this到流中,这里出现了一个问题。以下行不正确,因为this它是 type HierarchicalEntity,而不是T

parentsBuilder.add(this); // type mismatch!

如何重新设计界面以getAncestors()包含this在结果中?

4

3 回答 3

2

正如@SotiriosDelimanolis 所说,没有办法完全执行这一点。但是,如果您愿意假设接口按设计使用,您可以假设它this是一个实例T并简单地转换它:

parentsBuilder.add((T)this);

如果要避免强制转换,可以在子类中添加要覆盖的方法:

interface HierarchicalEntity<T extends HierarchicalEntity<T>> {
    T getParent();
    T getThis();
    default Stream<T> getAncestors() {
        // ...
        parentsBuilder.add(getThis());
        // ...
    }
}

class Foo extends HierarchicalEntity<Foo> {
    // ...
    @Override
    public Foo getThis() {
        return this;
    }
}

现在我们可以this采用类型安全的方式,但不能保证getThis()已正确实​​现。它可以返回任何Foo. 所以,我猜选择你的毒药。

于 2016-05-06T18:45:18.893 回答
2

创建自引用类型时,这是一个反复出现的问题。在基本类型(或接口)中,您不能强制this将赋值与T.

当然,如果您确信所有子类型都将满足该约束,则可以执行未经检查的thisto强制转换。但是,当您需要引用 asT时,您必须执行此未经检查的强制转换。thisT

更好的解决方案是添加一个抽象方法,例如

/**
    All subtypes should implement this as:

    public T myself() {
        return this;
    }
 */
public abstract T myself();

然后,您可以在需要自引用时使用,myself()而不是使用.thisT

default Stream<T> getAncestors() {
    Stream.Builder<T> parentsBuilder = Stream.builder();
    for(T node = myself(); node != null; node = node.getParent()) {
        parentsBuilder.add(parent);
    }
    return parentsBuilder.build();
}

当然,您不能强制子类正确实现myself()as return this;,但至少,您可以轻松地验证它们是否在运行时执行:

assert this == myself();

这个参考比较是一个非常便宜的操作,如果myself()正确地实现为总是返回this,HotSpot 可以预先证明这个比较永远是true并且完全省略了检查。

缺点是每个特化都必须有这种冗余实现myself() { return this; },但另一方面,它完全没有未经检查的类型转换。另一种方法是在基类中使用非abstract声明,以将未经检查的操作限制在类型层次结构的单个位置。但是,你无法验证是否真的是类型......</p> myself()@SuppressWarnings("unchecked") T myself() { return (T)this; }thisT

于 2016-05-09T10:03:11.407 回答
1

添加this失败,因为 aHierarchicalEntity<T>不一定是 a T; 它可能是一个未知的亚型。但是, aT始终是 a HierarchicalEntity<T>,因为您已经以这种方式声明了它。

更改fromgetAncestors和的返回类型to ,这将允许您添加.Stream.BuilderTHierarchicalEntity<T>this

default Stream<HierarchicalEntity<T>> getAncestors() {
    Stream.Builder<HierarchicalEntity<T>> parentsBuilder = Stream.builder();
    T parent = getParent();
    while (parent != null) {
        parentsBuilder.add(parent);
        parent = parent.getParent();
    }
    parentsBuilder.add(this);
    return parentsBuilder.build();
}

您可能希望声明getParent也返回 aHierarchicalEntity<T>以保持一致性。

于 2016-05-06T18:18:57.657 回答