1) Why new <String, String>My(1.1);
compiles? I explicitly defined that constructor has only one type parameter: public <R> My(R arg)
!
2) Why despite that I provide exact types (type witness) in constructor call (specifying the type argument R is String), new <String, String>My(1.1);
ignores it and the type is Double (<R>
= Double)?
3) Why in Runtime it is possible to understand the type of argument (Double) that was passed to constructor? Constructor is generic, so in Runtime no type information shall be available, only Object!?
class My<T,U> {
public <R> My(R arg) {
System.out.println(arg.getClass().getName());
}
}
public class Driver {
public static void main(String[] args) {
new My(1.1); // 1
new <String, String>My(1.1); // 2
}
}
Output:
java.lang.Double
java.lang.Double
P.S. I know JLS says that constructor's (or any method's) type witness(es) are ignored, if the constructor\method are not declared generic, and it is true for both cases (when the class itself generic, and the class itself is not generic). But in my example I can explicitly specify complete garbage to a generic\parametrized constructor as well!
Besides, the same code behaves differently if I make just one change - make the class NOT generic:
- wrong number of type parameters in constructor witness now gives compile error!
- wrong type of type parameters (not matching real argument) in constructor witness now also gives compile error!
But the output is still the same:
java.lang.Double
java.lang.Double
If class is generic, but created spesifying the types (new <String>My<Byte, Byte>(1.1);
), everything is exactly like above:
- wrong number of type parameters in constructor witness now gives compile error!
- wrong type of type parameters (not matching real argument) in constructor witness now also gives compile error!
Again, the output is still the same:
java.lang.Double
java.lang.Double
This answer is close to the topic, but is not clear and direct answer to issues here.