2

I am currently learning generics and having a hard time comprehending some aspects of them. I feel like I've overlooked something so the question might sound stupid.

I understand that there are:

  1. Placeholders, known as 'formal type parameters'.
  2. Actual 'type arguments'.

Here's a piece of sample code I have with generics and method chaining that works:

class Clothing <T> {
    String material; 
    String color; 

    T setMaterial (String material) {
        this.material = material;
        return (T) this;
    }

    T setColor (String color) {
        this.color = color;
        return (T) this;
    }

}

class Jeans extends Clothing <Jeans>  {

}

class Pants extends Clothing <Pants>  {

}


class Executor {

    public static void main(String[] args){
        Jeans jeansPair = new Jeans().setMaterial("cotton").setColor("green");
    }

}

The problem is I don't understand why the type arugment such as Jeans and Pants are provided in sub-class declarations instead of instantiations like the one in the main method.

I would appreciate if you provided a link to this rule--I've looked up a lot of info such as bounded parametrs, raw types, erasure etc. but did not quite find what I was looking for.

Thanks

Sam
  • 79
  • 6
  • 1
    This is Curiously Recurring Generic Pattern, or Template Pattern in c++ https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – flakes Apr 01 '16 at 13:41
  • 1
    You might want to look at this post as well http://stackoverflow.com/q/26762955/3280538 – flakes Apr 01 '16 at 13:44
  • 1
    This is also a way to allow an abstract base class to perform method chaining http://www.unquietcode.com/blog/2011/programming/using-generics-to-build-fluent-apis-in-java/ – flakes Apr 01 '16 at 13:51
  • @flkes Thanks, I will look into these links! – Sam Apr 01 '16 at 14:13

1 Answers1

0

Aside: you'd likely have an easier time with these generics if you used a builder pattern rather than the mutable pattern you're describing here. I just answered a related question that provides an example of such a builder structure.

Jeans and Pants are concrete types without a generic parameter, which is why when constructing them you simply say new Jeans() / new Pants(); they have no generic type the caller can specify. Since they also extend a generic type, you could say:

Clothing<Jeans> jeans = new Jeans()....;

if you wanted to refer to the object by its generic parent type. This is no different than any other parent/child type relationship, such as List<String> vs. ArrayList<String>. These classes simply hard-code the value of the generic type.

You could imagine copying the methods in Clothing into Jeans and Pants and replacing T with Jeans and Pants respectively, if that helps you see the what these classes are doing.

As to why the type argument is provided in sub-class declarations, it's a stylistic choice, there isn't a rule about when it should be used. It's nice when you have a finite number of types that can/should be used as the generic type, since now callers don't have to explicitly specify the type every time. However in the "generic" case where a generic type represents an arbitrary number of different concrete types this pattern is detrimental, since the class author needs to define a new subclass for every given type.

Community
  • 1
  • 1
dimo414
  • 47,227
  • 18
  • 148
  • 244