I\'m trying to switch a project to Java8, and encounter odd differences between Eclipse Luna and javac\'s type inference. With JDK 1.7.0_65 javac this code compiles just fin
Compilers can only inspect the method signatures, not the method body, so that part is irrelevant.
This "reduces" your code to (psuedocode):
public class TypeInferenceTest {
public static String toString(Object obj);
public static String toString(char[] ca);
public static String toString(Throwable t);
public static U getKey(Object code, U defaultValue);
public static void test() {
Object code = "test";
toString(getKey(code, null));
}
}
Also note that the U getKey(...)
really is: U getKey(...)
.
All it knows that getKey(code, null)
returns is: ? extends Object
, so it returns a subtype of Object
, or an Object
itself.
There are three signatures that match, namely Object
, char[]
and Throwable
, where both char[]
and Throwable
match equally and better than Object
, because you asked for an ? extends Object
.
So it cannot choose which is the correct one, because all three match the signature.
When you change it to:
public static Object getKey(Object code, Object defaultValue);
then only public static String toString(Object obj);
matches, because it matches better as any other ? extends Object
that is not equal to Object
.
Edit, I looked over the original intent of the question: Why does it compile in Java 7, but not in Java 8?
In Java 8 type inference got greatly improved.
Whereas in Java 7 it could for example only infer that getKey
returned an Object
, it now in Java 8 infers that it returns an ? extends Object
.
When using Java 7 there was only one match, namely Object
.
To have the change visualized even better, consider this piece of code:
public class TypeInferenceTest {
public static String toString(Object obj) { return "1"; }
public static String toString(Throwable t) { return "2"; }
public static U getKey(Object code, U defaultValue) { return defaultValue; }
public static void test() {
Object code = "test";
String result = toString(getKey(code, null));
System.out.println(result);
}
public static void main(String[] args) {
test();
}
}
On Java 7 it prints 1
, on Java 8 it prints 2
, exactly because of the reasons I have outlined above.