如何使用Java泛型两次扩展构建器类?

时间:2016-07-15 07:27:20

标签: java generics inheritance nested-generics

我有一个我想要扩展的构建器类,这是简单的版本:

class A {
    public A withSomeAStuff() {
        return this;
    }
}
A a = new A().withSomeAStuff();

当我扩展它时,我知道我可以毫无问题地做到这一点:

class AA<T extends AA> {
    public T withSomeAStuff() {
        return (T) this;
    }
}
class BB extends AA<BB> {
    public BB withSomeBStuff() {
        return this;
    }
}
AA aa = new AA().withSomeAStuff();
BB bb = new BB().withSomeAStuff().withSomeBStuff();

但是现在我想用另一个类进一步扩展它,所以我试试这个:

class AAA<T extends AAA> {
    public T withSomeAStuff() {
        return (T) this;
    }
}
class BBB<T extends BBB> extends AAA<T> {
    public T withSomeBStuff() {
        return (T) this;
    }
}
class CCC extends BBB<CCC> {
    public CCC withSomeCStuff() {
        return this;
    }
}
AAA aaa = new AAA().withSomeAStuff();
BBB bbb = new BBB().withSomeAStuff().withSomeBStuff(); //breaks here!
CCC ccc = new CCC().withSomeAStuff().withSomeBStuff().withSomeCStuff();

我的新CCC课程工作正常,但我的BBB课程坏了,我无法弄明白为什么。

我需要做些什么来解决它?

2 个答案:

答案 0 :(得分:2)

当您在类型声明中引入泛型时,也可以在创建该类型的对象时使用它。

    AAA<AAA> aaa = new AAA<>().withSomeAStuff();
    BBB<BBB> bbb = new BBB<>().withSomeAStuff().withSomeBStuff(); //Does not break anymore.
    CCC ccc = new CCC().withSomeAStuff().withSomeBStuff().withSomeCStuff();

注意: 虽然这将解决您的编译器错误,但这不是一种万无一失的方式,并保证在每种情况下都能正常工作。您将收到编译器警告以确认。

例如,你可以这样做,

BBB<CCC> bbb = new BBB<CCC>().withSomeAStuff().withSomeBStuff();

在运行期间受到冲击。

答案 1 :(得分:1)

永远不要忽略原始类型警告:What is a raw type and why shouldn't we use it?

我添加了一个方法self(),因此您的代码中只有一个未经检查的强制转换。

class AAA<T extends AAA<T>> {
    public T withSomeAStuff() {
        return self();
    }

    @SuppressWarnings("unchecked")
    protected T self() {
        return (T) this;
    }
}

class BBB<T extends BBB<T>> extends AAA<T> {
    public T withSomeBStuff() {
        return self();
    }
}

class CCC extends BBB<CCC> {
    public CCC withSomeCStuff() {
        return this;
    }
}


public static void main(String[] args) {
    AAA<?> aaa = new AAA<>().withSomeAStuff();
    BBB<?> bbb = new BBB<>().withSomeAStuff().withSomeBStuff(); 
    CCC ccc = new CCC().withSomeAStuff().withSomeBStuff().withSomeCStuff();
}