我有一个父类Builder
,可以使用Builder
类型的参数或其子类型进行生成:
class Builder<T extends Builder> {
@SuppressWarnings("unchecked")
T doSmth() {
System.out.println("do smth");
return (T)this;
}
}
它有一个子类 - BuilderChild
:
class BuilderChild extends Builder<BuilderChild> {
BuilderChild doSmthElse() {
System.out.println("do smth else");
return this;
}
}
因此,我可以在doSmth
个实例上调用方法BuilderChild
,然后返回BuilderChild
:
new BuilderChild().doSmth().doSmthElse();
但是当我试图通过BuilderChild
生成上面的行停止编译时。
class BuilderChild<T> extends Builder<BuilderChild> {
BuilderChild doSmthElse() {
System.out.println("do smth else");
return this;
}
}
...
//Compile error, because doSmth()
//returns Builder instead of BuilderChild.
new BuilderChild().doSmth().doSmthElse();
有人解释为什么doSmth()
在我提出Builder
之后开始返回BuilderChild
?有没有办法解决它?
答案 0 :(得分:5)
问题在于您使用BuilderChild
作为原始类型。
这意味着它具有类型参数,但您指定它而不提供任何类型参数。
这意味着几乎所有该类型的泛型信息都将被忽略(它是a bit more complicated than that,但这是高级视图。)
如果你这样写:
new BuilderChild<Object>().doSmth().doSmthElse();
然后编译。
此外,doSmthElse
应指定为BuilderChild<T> doSmthElse()
。
请注意,原始类型仅支持向后兼容性,不应在新代码中使用。
答案 1 :(得分:0)
我建议做类似的事情:
abstract class Builder<T extends Builder> {
protected T getThis();
@SuppressWarnings("unchecked")
T doSmth() {
System.out.println("do smth");
return getThis();
}
}
class BuilderChild extends Builder<BuilderChild> {
protected T getThis() { return this; }
[...]
虽然客户端代码最好不要使构建器非通用。