I was reading this article, https://weblogs.java.net/blog/emcmanus/archive/2010/10/25/using-builder-pattern-subclasses, about subclassing a builder class. I understood the article but there was one small bit that bothered me. There was this method,
public static Builder<?> builder() {
return new Builder2();
}
When I changed Builder<?>
to Builder
, a raw type, the compiler would not compile the code. What is the additional information was passed to the compiler via with the additional <?>
?
I have pasted the code here:
public class Shape {
private final double opacity;
public static class Builder<T extends Builder<T>> {
private double opacity;
public T opacity(double opacity) {
this.opacity = opacity;
return self();
}
/*
public T height(double height) {
System.out.println("height not set");
return self();
}
*/
protected T self() {
System.out.println("shape.self -> " + this);
return (T) this;
}
public Shape build() {
return new Shape(this);
}
}
public static Builder<?> builder() {
return new Builder();
}
protected Shape(Builder builder) {
this.opacity = builder.opacity;
}
}
public class Rectangle extends Shape {
private final double height;
public static class Builder<T extends Builder<T>> extends Shape.Builder<T> {
private double height;
public T height(double height) {
System.out.println("height is set");
this.height = height;
return self();
}
public Rectangle build() {
return new Rectangle(this);
}
}
public static Builder<?> builder() {
return new Builder();
}
protected Rectangle(Builder builder) {
super(builder);
this.height = builder.height;
}
public static void main(String[] args) {
Rectangle r = Rectangle.builder().opacity(0.5).height(250).build();
}
}
2
If you remove the generic part <?>
of Builder<?>
, all generic information is removed and the T
in your Builder
class becomes Object
– Object
does not have an opacity()
method.
4
The ?
symbol is a type variable. It’s an unnamed one, meaning you can’t refer to it in code, but the compiler still is going to use it, and substitute it with the actual type your Builder
works with (such as Rectangle
). The compiler can then use this additional type information, including the proper resolution of the opacity
method.
Without <?>
, this additional compile-time type information is lost, thus compiler needs to assume it works with plain Object
. As a result, you’d explicit casting to invoke any method that Object
class does not have.