0

So I have the following code that I have been playing around with to try to understand recursive generics.

class Person
{
    public String name;
    public String position;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", position='" + position + '\'' +
                '}';
    }

}

//This is called a recursive generic.
class PersonBuilder<SELF extends PersonBuilder<SELF>>
{
    protected Person person = new Person();

    public SELF withName(String name)
    {
        person.name = name;
        //System.out.println(this.getClass());
        //System.out.println(self().getClass());
        return self();
    }

    public Person build()
    {
        return person;
    }

    protected SELF self()
    {
        return (SELF) this;
    }


}

class EmployeeBuilder extends PersonBuilder<EmployeeBuilder>
{
    public EmployeeBuilder worksAt(String position)
    {
        person.position = position;
        return self();
    }
    @Override
    protected EmployeeBuilder self()
    {
        return this;
    }
}

class Demo1
{
    public static void main(String[] args) {
        EmployeeBuilder eb = new EmployeeBuilder();

        Person richard = eb.withName("Richard")
                            .worksAt("Programmer")
                            .build();
        System.out.println(richard);

        PersonBuilder pb = new PersonBuilder<>();
        Person bob = pb.withName("Bob").build();

    }
}

I have a few questions related to the above implementation.

  1. Why is this called a recursive generic? Is it recursive because the Parent class has a Child class as the generic? I understand that the goal is that we need to return an Object of the Child class in the inherited withName method to be able to call methods in both the Child and Parent classes.

  2. What is the difference between PersonBuilder<SELF> and PersonBuilder? For instance, I created a PersonBuilder object in the main method with PersonBuilder pb = new PersonBuilder<>(). What is implied in the <> here if it's just the Parent class?

  • Does the generic "disappear" somehow? I am asking this because when I printed class using this.getClass() I only got PersonBuilder as the class, which is why I am thinking somehow the generic is gone. On the other hand, since the class signature has the generic attached to it, I have a feeling it must be lurking somewhere.
  1. What is the difference if I changed the class signature to class PersonBuilder<SELF extends PersonBuilder>? I ran the code with this change and it still worked. I have a feeling it has something to do with being consistent, but I do not have enough insight into what is going on to see how this makes a difference.

Thanks for your help.

omajid
  • 14,165
  • 4
  • 47
  • 64
Richard K Yu
  • 2,152
  • 3
  • 8
  • 21
  • Most of your questions boil down to "raw types" and "type erasure". It's called a recursive generic (or a self-referential generic) because the upper bound on `SELF` contains `SELF`. – Andy Turner Feb 02 '22 at 09:45

1 Answers1

2

Java actually gives you the freedom to use raw types.

As for example if PersonBuilder (without an angular bracket <> ) is a raw type, that is the generic part of it is not defined.

There is a way something like this

List<?> someList = getList(); // Assume an API exists which returns a list, but of what type is unknown, that is a wild card.

As part of Q2. PersonBuilder pb = new PersonBuilder<>()

This is simply a raw type reference which holds a generic type object ( java dosen't restrict you to do this, mainly for backward compatibility, but is not recommended to be used)

generic "disappear" somehow - Actually the generic type is a run time thing, but the class is available at the compile time.

The getClass will always give you the class and not its generic type. There is a way, to get the generic type but that is using some reflection.

You can look into this ques, for details of how to retrieve the generic type at runtime. Get generic type of class at runtime