1

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
  • 2
    AFAIK this should only cause a warning. Is your compiler configured to stop on warnings? What was the error message?
    – tobias_k
    Commented Mar 19, 2014 at 9:06
  • Change Builder<?> to Builder you will see the error, Rectangle.java:33: error: cannot find symbol System.out.println(Rectangle.builder().opacity(0.5).height(250);
    – thlim
    Commented Mar 19, 2014 at 10:21

2 Answers 2

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
  • This was what I suspected. I am looking for more information regarding this. An URL to an article explaining this behavior would be perfect
    – thlim
    Commented Mar 19, 2014 at 12:08
  • @thlim Actually I think my answer is incorrect. You would probably get more and better answers on stackoverflow.
    – assylias
    Commented Mar 19, 2014 at 12:17
  • Off topic, sometimes I am confused as to where I should post my questions. One time I was suggested to post here instead SO for question like this. Nevertheless SO has more audience.
    – thlim
    Commented Mar 20, 2014 at 2:53
  • 1
    To simplify, SO is for questions about specific issues with a specific piece of code. Programmers is for higher level question such as design and architecture, algorithms etc. So in this instance SO would probably be a better fit.
    – assylias
    Commented Mar 20, 2014 at 4:03
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.