我必须为分层实体设计一个接口:
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
的类型为HierarchicalEntity
,而非T
:
parentsBuilder.add(this); // type mismatch!
如何重新设计界面,以便getAncestors()
在结果中包含this
?
答案 0 :(得分: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
的任何实例。所以,我猜你的毒药。
答案 1 :(得分:2)
创建自引用类型时,这是一个反复出现的问题。在基本类型(或界面)中,您无法强制this
与[{1}}分配兼容。
当然,如果您确信所有子类型都能满足该约束条件,则可以执行T
到this
的未经检查的转换。但是,只要您需要T
引用this
,就必须执行此未经检查的转换。
更好的解决方案是添加一个像
这样的抽象方法T
然后,只要您需要/**
All subtypes should implement this as:
public T myself() {
return this;
}
*/
public abstract T myself();
进行自我引用,就可以使用myself()
代替this
。
T
当然,您不能强制执行该子类正确实现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()
,但至少,您可以轻松验证它们是否在运行时执行:
return this;
这个参考比较是一个非常便宜的操作,如果assert this == myself();
被正确实现,总是返回myself()
,HotSpot可以事先证明这个比较总是this
并且忽略完全检查。
缺点是每个专业化必须具有true
的冗余实现,但另一方面,它完全没有未经检查的类型转换。另一种方法是在基类中将myself() { return this; }
声明为abstract
作为myself()
,以将未经检查的操作限制为类型层次结构的单个位置。但是,您无法验证@SuppressWarnings("unchecked") T myself() { return (T)this; }
是否真的属于this
...
答案 2 :(得分:1)
添加this
失败,因为HierarchicalEntity<T>
不一定是T
;它可能是一个未知的亚型。但是,T
始终是HierarchicalEntity<T>
,因为您已经这样声明了。
将getAncestors
和Stream.Builder
的返回类型从T
更改为HierarchicalEntity<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
也返回HierarchicalEntity<T>
以保持一致。