2

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:

  1. wrong number of type parameters in constructor witness now gives compile error!
  2. 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:

  1. wrong number of type parameters in constructor witness now gives compile error!
  2. 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.

Code Complete
  • 3,146
  • 1
  • 15
  • 38
  • 3
    Your class instance creation expressions are for the raw type `My`. All generics are ignored. Get rid of your class type parameters `T` and `U` and compilation will fail, for 2. – Sotirios Delimanolis Oct 13 '17 at 16:24
  • For your point 3: your code passes a `Double` into the constructor and then prints out the class of that object. The object that you have passed in does not somehow loose its type just because of generics. – Thomas Kläger Oct 13 '17 at 16:31
  • If you’re compiling on the command line, use the `-Xlint` option. If using an IDE, enable all compiler warnings. Either way, that will show you what the compiler really thinks of your invocations. – VGR Oct 13 '17 at 16:36
  • Wow. I get that it's a raw type thing, but even with raw types, I would not have expected it to allow 2 type parameters on a constructor that takes 1. – user2357112 Oct 13 '17 at 16:59

0 Answers0