Invoking Java Generic Methods
generic-method, generics, java, type-erasure
Solution
The answer seems to go beyond @Telthien and @newacct' answers. I was curious to "see" for myself the difference between:
System.out.println(Util.<String>compare("a", "b"));
with explicity typing, and:
System.out.println(Util.compare(new String(""), new Long(1)));
with implicit typing.
I performed several experiments, using variations on these two previous lines. These experiments show that, short of using the anonymous/local class trick, the compiler does check the types during compilation but the generated bytecodes only refer to `Object`, even in the case of the first line.
The following piece of code shows that typecasts can be performed safely all the way to `Object` even in the case of the explicity type argument `<String>`.
public final class Example44 {
public static void main(final String[] args) {
System.out.println(new Util44<String>().compare("a", "b"));
System.out.println(new Util44().compare(new String(""), new Long(1)));
}
}
final class Util44<T> {
private T aT;
public boolean compare(T t1, T t2) {
System.out.println(this.aT);
// I was expecting the second and third assignments to fail
// with the first invocation because T is explicitly a String
// and then to work with the second invocation because I use
// a raw type and the compiler must infer a common type for T.
// Actually, all these assignments succeed with both invocation.
this.aT = (T) new String("z");
this.aT = (T) new Long(0);
this.aT = (T) new Object();
return t1.equals(t2);
}
}
The bytecodes of the `main` method look like:
// Method descriptor #15 ([Ljava/lang/String;)V
// Stack: 7, Locals: 1
public static void main(java.lang.String[] args);
0 getstatic java.lang.System.out : java.io.PrintStream [16]
3 new ca.polymtl.ptidej.generics.java.Util44 [22]
6 dup
7 invokespecial ca.polymtl.ptidej.generics.java.Util44() [24]
10 ldc <String "a"> [25]
12 ldc <String "b"> [27]
14 invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29]
17 invokevirtual java.io.PrintStream.println(boolean) : void [33]
20 getstatic java.lang.System.out : java.io.PrintStream [16]
23 new ca.polymtl.ptidej.generics.java.Util44 [22]
26 dup
27 invokespecial ca.polymtl.ptidej.generics.java.Util44() [24]
30 new java.lang.String [39]
33 dup
34 ldc <String ""> [41]
36 invokespecial java.lang.String(java.lang.String) [43]
39 new java.lang.Long [46]
42 dup
43 lconst_1
44 invokespecial java.lang.Long(long) [48]
47 invokevirtual ca.polymtl.ptidej.generics.java.Util44.compare(java.lang.Object, java.lang.Object) : boolean [29]
50 invokevirtual java.io.PrintStream.println(boolean) : void [33]
53 return
Line numbers:
[pc: 0, line: 24]
[pc: 20, line: 25]
[pc: 53, line: 26]
Local variable table:
[pc: 0, pc: 54] local: args index: 0 type: java.lang.String[]
It actually makes sense that all the calls are always to methods with `Object` as formal parameter types, as explained in another question/answer. To conlude, the compiler always uses `Object` for the generated bytecodes, not matter if there is an explicity type argument (first line) or an implicit type argument but that the objects could have a common superclass different from `Object`.
Problem
I am studying Java generic feature and I am not sure how to explain the third line in the following `main` method: ``` public class Example4 { public static void main(final String[] args) { System.out.println(Util.<String>compare("a", "b")); System.out.println(Util.<String>compare(new String(""), new Long(1))); System.out.println(Util.compare(new String(""), new Long(1))); } } class Util { public static <T> boolean compare(T t1, T t2) { return t1.equals(t2); } } ``` The first line compiles, runs, and returns (as expected) `false`. The second line does not compile as expected, because I am explicitely mixing `String` and `Long`. The third line compiles, runs, and return false but I am not sure to understand how it happens to work: does the compiler/JVM instantiates the parameter type `T` as `Object`? (Also, would there be a way to obtain this declared type of `T` are runtime?) Thank you.