For a method of type T, what should be its type "deduced" when two <? super T> arguments?
There is a method in the hamcrest library:
package org.hamcrest.core ... public static <T> Matcher<T> allOf(Matcher<? super T> first, Matcher<? super T> second) { List<Matcher<? super T>> matchers = new ArrayList<Matcher<? super T>>(2); matchers.add(first); matchers.add(second); return allOf(matchers); } In my code, I call this method first Matcher<Object> and second Matcher<SomeException> .
And now:
- When I compile it with Eclipse with a 1.6 target, it makes a
<T>Matcher<SomeException>. - When I compile it with javac 1.7 with a 1.6 target, it makes a
<T>Matcher<SomeException>. - When I compile it with javac 1.6 with a 1.6 target, it makes a
<T>Matcher<Object>
The question is, what should <T> be in that case?
I understand that there is an error in javac 1.6, and it should be Matcher<SomeException> , since this is a common type of input arguments (SomeException is a subtype of Object), and then it is 100% sure that the Matcher Returned will be Matcher<SomeException> .
I'm right? And is there a way to get Javac 1.6 to behave properly?
The compiler will produce output based on the actual arguments . It starts with the initial constraints of Matcher<Object> << Matcher<? super T> Matcher<Object> << Matcher<? super T> and Matcher<SomeException> << Matcher<? super T> Matcher<SomeException> << Matcher<? super T> . From this we derive the constraints T << Object and T << SomeException . Object will be eliminated when the minimum erased candidate set is configured. The rest of the SomeException candidate will (eventually: D) be replaced by T
So far, we have shown that Eclipse and JDK7 behave correctly in this case. I don't think there is a way to get Javac to behave properly. You can either explicitly specify a type argument or use JDK7 (specify source and target as 6).
There are two things you should consider:
First you can use it like this:
CoreMatcher.<SomeException>allOf(...), which explicitly setsTSecondly, due to type erasure, you ALWAYS have a
Matcher<Object>as the runtime. Therefore, in any case, the runtime behavior is the same.