Reputation: 819
Based on the java documentation:
During the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.
Now, the thing is, with a class like that:
public class MyCreator<T> {
Class<T> kind;
MyCreator(Class<T> kind) {
this.kind = kind;
}
void printInstanceClass() throws Exception{
System.out.println(kind.newInstance().getClass());
}
public static void main(String[] args) throws Exception{
MyCreator<String> myCreator = new MyCreator<String>(String.class);
myCreator.printInstanceClass();
}
}
the printInstanceClass()
method is printing actually "class java.lang.String".
If the compiler is replacing T inside of the class with Object, I guess that also the information on Class associated with kind
is removed and replaced with Class. So, how can the newInstance()
method return a String instance instead of an Object one?
Upvotes: 1
Views: 81
Reputation: 7166
The tricky part is the String.class
parameter. It's not a type parameter, but a plain old param, like String[] args
. So, the Class<T> kind
will be String.class
thus the printInstanceClass()
can access it at runtime.
It's a common practice, suggested in Effective Java too.
So after type erasure this code is logically equivalent to this one:
public class MyCreator {
Class kind; // this will be String.class at runtime
MyCreator(Class kind) {
this.kind = kind;
}
void printInstanceClass() throws Exception{
System.out.println(kind.newInstance().getClass());
}
public static void main(String[] args) throws Exception{
MyCreator myCreator = new MyCreator(String.class);
myCreator.printInstanceClass();
}
}
Upvotes: 2
Reputation: 3426
Information about the class (type) you passed as generic argument of your myCreator
object is erased, but not information stored inside the kind
object.
Using Class<?>
object methods is fine, but if you tried to obtain class information from generic T
type you'd encounter a compilation error, for instance:
void printInstanceClass() throws Exception{
System.out.println(T.class.newInstance().getClass()); // error!
}
Although it's not easy, workarounds for doing the above exist too.
Upvotes: 1
Reputation: 3554
You pass String.class (which is NOT erased, but a concrete class retained at runtime), then call newInstance on that class, which yields a String.
The output examines the concrete object (String) and displays its class.
Upvotes: 2