为分层实体设计接口

Ali*_*der 7 java interface hierarchical java-8 default-method

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

interface HierarchicalEntity<T extends HierarchicalEntity<T>> {
    T getParent();
    Stream<T> getAncestors();
}
Run Code Online (Sandbox Code Playgroud)

以前者将返回所有祖先的方式实现默认 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();
}
Run Code Online (Sandbox Code Playgroud)

但是我还需要包含this在流中,这里出现问题.以下行不正确,因为this它是类型HierarchicalEntity,而不是T:

parentsBuilder.add(this); // type mismatch!
Run Code Online (Sandbox Code Playgroud)

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

Hol*_*ger 2

创建自引用类型时,它\xe2\x80\x99 是一个反复出现的问题。在基本类型(或接口)中,您可以\xe2\x80\x99t 强制执行thisT.

\n\n

当然,如果您确信所有子类型都满足该约束,则可以执行thisto的未经检查的强制转换。T但是,只要您需要引用thisas ,就必须执行这种未经检查的转换T

\n\n

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

\n\n
/**\n    All subtypes should implement this as:\n\n    public T myself() {\n        return this;\n    }\n */\npublic abstract T myself();\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
default Stream<T> getAncestors() {\n    Stream.Builder<T> parentsBuilder = Stream.builder();\n    for(T node = myself(); node != null; node = node.getParent()) {\n        parentsBuilder.add(parent);\n    }\n    return parentsBuilder.build();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
assert this == myself();\n
Run Code Online (Sandbox Code Playgroud)\n\n

这种引用比较是一种非常便宜的操作,如果myself()正确实现为总是返回this,HotSpot 可以提前证明这种比较将始终是true并且完全消除检查。

\n\n

缺点是每个专门化都必须有 的冗余实现myself() { return this; },但另一方面,它\xe2\x80\x99s 完全没有未经检查的类型转换。另一种方法是在基类中进行非abstract声明,以将未经检查的操作限制在类型层次结构的单个位置。但是,你可以\xe2\x80\x99t验证是否真的是\xe2\x80\xa6类型myself()@SuppressWarnings("unchecked") T myself() { return (T)this; }thisT

\n