Для метода типа T, каким должен быть его "выводимый" тип, когда он принимает два аргументы?
В библиотеке hamcrest есть метод:
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);
}
В моем коде я вызываю этот метод с first
бытием Matcher<Object>
и second
бытием Matcher<SomeException>
.
А теперь:
- когда я компилирую его с Eclipse с 1.6 target, он делает
<T>
Matcher<SomeException>
. - когда я компилирую его с javac 1.7 с 1.6 target, он делает
<T>
Matcher<SomeException>
. - когда я компилирую его с javac 1.6 с 1.6 target, он делает
<T>
Matcher<Object>
Вопрос в том, что <T>
должно быть в таком случае?
Я понимаю, что в javac 1.6 есть ошибка, и она должна быть Matcher<SomeException>
, так как это общий тип для входных аргументов (SomeException-подтип объекта), и тогда, это 100% уверен, что возвращаемый Matcher будет Matcher<SomeException>
.
Я прав? И есть ли способ заставить javac 1.6 вести себя должным образом?
2 ответа:
Компилятор сделает вывод, основанный на фактических аргументах . Он будет начинаться с начальных ограничений
Matcher<Object> << Matcher<? super T>
иMatcher<SomeException> << Matcher<? super T>
. Из этого он выведет ограниченияT << Object
иT << SomeException
.Object
будет исключен, когда будет построено минимальное стертое множество кандидатов . Оставшийся кандидатSomeException
будет (в конечном счете: D) заменен наT
.До сих пор мы показывали, что eclipse и JDK7 ведут себя правильно в этом случае. Я не думаю, что есть какой-либо способ заставить джавака сделать это. вести себя правильно. Вы можете либо явно указать аргумент типа, либо использовать JDK7 (указав source и target равными 6).
Есть две вещи, которые вы должны рассмотреть:
Сначала вы можете использовать его следующим образом:
CoreMatcher.<SomeException>allOf(...)
, который явно устанавливаетT
.Во-вторых, из-за стирания типа, в качестве времени выполнения у вас всегда есть
Matcher<Object>
. Так что в любом случае поведение во время выполнения одинаково.