I see that the question is about the <T>
part in Builder<T>
. Without this <T>
, you simply get a raw type, and your IDE might complain.
But in my answer, I'd like to explain what's the purpose of T extends Builder<T>
, because other answers do not seem to cover it (maybe you know this already).
T extends Builder<T>
serves the purpose of returning appropriate Builder.this
in all the Builder
methods (except build()
method, of course).
I usually use it with a protected abstract method like T thisInstance()
.
Example:
abstract class NamedBuilder<T extends NamedBuilder<T>> {
private String name;
T name(String name) {
this.name = name;
return thisInstance();
}
protected abstract T thisInstance();
}
final class MoreSpecificBuilder extends NamedBuilder<MoreSpecificBuilder> {
@Override
protected MoreSpecificBuilder thisInstance() {
return this;
}
}
Thanks to such approach, you do not have to redefine name()
method in all the NamedBuilder
subclasses to return the specific subclass.
Without such constraint type parameter T
, you would have:
abstract class NamedBuilder {
NamedBuilder name(String name);
}
and you would need to override all such methods in subclasses like that:
final class MoreSpecificBuilder extends NamedBuilder {
@Override
MoreSpecificBuilder name(String name) {
super.name(name);
return this;
}
}
EDIT: Without the constraint extends Builder<T>
on type parameter T
:
abstract class NamedBuilder<T> {
// ...
}
this would work fine, although such design would be less intuitive and more error-prone.
Without such constraint, compiler would accept anything as T
(e.g. String
), so the constraint acts simply as a compile-time check for the implementors of NamedBuilder
.