泛化的类和继承问题

时间:2010-12-17 12:46:14

标签: java oop generics inheritance

我有一个父类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?有没有办法解决它?

2 个答案:

答案 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; }
    [...]

虽然客户端代码最好不要使构建器非通用。