简体   繁体   中英

Type Erasure and the Return type

class Person
{
    String name;
    String add;

    Person(){}

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

    public Person(String name, String add)
    {
        this.name=name;
        this.add=add;
    }
}


class PersonBuilder<E extends PersonBuilder<E>>{
    String name;
    String add;

    E addName(String name)
    {
        this.name=name;
        return (E)this;
    }
    E addAdd(String add)
    {
        this.add=add;
        return (E)this;
    }
    Person build()
    {
        return new Person(name,add) ;
    }
}

class Employee extends Person{
    String doj;

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", add='" + add + '\'' +
                ", doj='" + doj + '\'' +
                '}';
    }

    Employee(String name, String add, String doj)
    {
        super(name,add);
        this.doj=doj;
    }


}
class EmployeeBuilder extends PersonBuilder<EmployeeBuilder>{

    String doj;
    EmployeeBuilder addDoj(String doj)
    {
        this.doj=doj;
        return this;
    }
    Employee build()
    {
        return new Employee(name,add,doj);
    }
}

public class FluentBuilderRecursiveGenerics{
    public static void main(String[] args) {
 1.       EmployeeBuilder eb=new EmployeeBuilder();
 2.       Employee e=eb.addName("kamal").addAdd("dcd").addDoj("45").build();
 3.       System.out.println(e);

 4.       PersonBuilder pb=new PersonBuilder();
 5.       Person p=pb.addName("Kamal").addAdd("dlf").build();
 6.       System.out.println(p);
    }
}

I have two questions to ask in these lines of code. The lines of code are related to the Fluent(design pattern) Recursive Generics. First is as Line 1, 2, 3 are running that means the Return type of PersonBuilder method is EmployeeBuilder, but I have also studied that the type erasure replaces the type with the bounds, So it should be replacing with PersonBuilder(EmployeeBuilder) and the program should not be running. Because when in case of generics the input parameters of a function will be decided by the type Erasure. The other question is what type Erasure is going to do for the line Number 4,5,6. Can anyone explain?

Output:

Employee{name='kamal', add='dcd', doj='45'}
Person{name='Kamal', add='dlf'}
  • 4, 5, 6:

    Here there is no generic type parameter, hence the compiler will fallback on the pre-generics behavior. No type-safeness. In effect it shows a design flaw here.

  • 1, 2, 3:

    Type erasure results in a runtime cast to EmployeeBuilder of the PersonBuilder object at addDoj .

About the pattern implementation and the parametrisation with the actual child class:

One can use the language feature that an overriden method may return any child class of the super method. This makes generic typing unneeded, but does not enforce the return type being the exact child class. And requires all methods in every child class to be overriden.

public class A {
    String name;
    A addName(String name) {
        this.name = name;
        return this;
    }
}

class B extends A {
    @Override
    B addName(String name) {
        return (B) super.addName(name);
    }
}

public static void main(String args[]) {
  B b = new B().addName("xxx");
  System.out.println("name = " + b.name);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM