Reputation: 455
I have a builder class that I want to extend, here is the simple version:
class A {
public A withSomeAStuff() {
return this;
}
}
A a = new A().withSomeAStuff();
When I extend it, I know that I can do this without any problem:
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();
But now I want to extend it further with another class, so I try this:
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();
My new CCC class works fine, but my BBB class is broken and I cannot figure out why.
What do I need to do to fix it?
Upvotes: 2
Views: 163
Reputation: 5558
Never ignore raw type warnings: What is a raw type and why shouldn't we use it?
I added a method self()
so you only have a single unchecked cast in your code.
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();
}
Upvotes: 1
Reputation: 14471
When you introduce generics in the type declaration, then use it while creating objects of the type too.
AAA<AAA> aaa = new AAA<>().withSomeAStuff();
BBB<BBB> bbb = new BBB<>().withSomeAStuff().withSomeBStuff(); //Does not break anymore.
CCC ccc = new CCC().withSomeAStuff().withSomeBStuff().withSomeCStuff();
Note: While this will solve your compiler error, this is not a foolproof way and guaranteed to work in every case. You will get compiler warnings to confirm that.
For example you could do,
BBB<CCC> bbb = new BBB<CCC>().withSomeAStuff().withSomeBStuff();
and get a shock during runtime.
Upvotes: 2