Compilers can only check method signatures, not the method body, so the part does not matter.
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> U getKey(Object code, U defaultValue); public static void test() { Object code = "test"; toString(getKey(code, null)); } }
Also note that <U> U getKey(...) is actually: <U extends Object> U getKey(...) .
All that is known is that getKey(code, null) returns ? extends Object ? extends Object , therefore returns a subtype of Object or the Object itself.
There are three signatures that match, namely Object , char[] and Throwable , where both char[] and Throwable match the same and better than Object , because you asked ? extends Object ? extends Object .
Therefore, he cannot choose which one is correct, because all three correspond to the signature.
When you change it to:
public static Object getKey(Object code, Object defaultValue);
it matches only public static String toString(Object obj); because it better matches any other ? extends Object ? extends Object , which is not equal to Object .
Edit , I looked at the original intent of the question: why does it compile in Java 7, but not in Java 8?
As a result, input like Java 8 has improved significantly.
While in Java 7 it can, for example, conclude that getKey returned Object , now in Java 8 it reports what it returns ? extends Object ? extends Object .
When using Java 7, there was only one match, namely Object .
To visualize the changes 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> 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 precisely for the reasons stated above.