【发布时间】:2015-05-21 19:36:43
【问题描述】:
我经常发现自己想要编写格式为
的通用类定义public class Foo<ActualType extends Foo<ActualType>>
例如在这样的设置中:
public interface ChangeHandler<SourceType> {
public void onChange(SourceType source);
}
public class Foo<ActualType extends Foo<ActualType>> {
private final List<ChangeHandler<ActualType>> handlers = new ArrayList<>();
public void addChangeHandler(ChangeHandler<ActualType> handler) {
handlers.add(handler);
}
@SuppressWarnings("unchecked")
protected void reportChange() {
for (ChangeHandler<ActualType> handler: handlers)
handler.onChange((ActualType) this);
}
}
public class Bar extends Foo<Bar> {
// things happen in here that call super.reportChange();
}
public static void main(String[] args) throws IOException {
Bar bar = new Bar();
bar.addChangeHandler(new ChangeHandler<Bar>() {
@Override
public void onChange(Bar source) {
// Do something with the changed object
}
});
}
这里的更改事件只是一个示例。每当我想允许超类为每个特定的子类提供“个性化”的功能时,这更像是一个普遍的问题(不知道如何更好地表达这一点......在示例中在“个性化”之上的事实是,ChangeHandler 是使用实际子类型 (Bar) 的对象而不是调用处理程序的超类 (Foo) 的类型调用的。
不知何故,这种方法对我来说似乎有点混乱。它实际上允许潜在的问题,因为没有什么能阻止我定义:
public class Baz extends Foo<Bar> { /* ... */ }
有更清洁的替代品吗?
圣杯将是一些始终定义为包含当前类的类型参数,例如 this.getClass() 的静态版本,它允许我编写类似这样的内容:
public class Foo {
private final List<ChangeHandler<this.Class>> handlers = new ArrayList<>();
public void addChangeHandler(ChangeHandler<this.Class> handler) {
handlers.add(handler);
}
protected void reportChange() {
for (ChangeHandler<this.Class> handler: handlers)
handler.onChange(this);
}
}
对于 Bar 类型的类,this.Class 将等于 Bar。
【问题讨论】:
-
这是 Java 版本的 CRTP。这很典型。
-
圣杯会很好,但它不存在(还)。由于继承,静态检查似乎很困难。
-
你不能做
Foo<T extends Foo<?>>,用T替换所有出现的ActualType吗?不再需要ActualType。不确定这是否是您所说的“更清洁” -
@Radiodef 也许可以隐式地将
<ActualType extends Foo<ActualType>>构造添加到每个类定义中并以这种方式处理它? -
很难静态检查的情况是这样的:假设你有一个
class Foo { void m(this.Class in) {} }和一个class Bar extends Foo {}。现在假设您有一个Foo foo = new Bar();。foo.m应该接受什么类型?