Для метода типа 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 7

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).

Есть две вещи, которые вы должны рассмотреть:

  1. Сначала вы можете использовать его следующим образом: CoreMatcher.<SomeException>allOf(...), который явно устанавливает T.

  2. Во-вторых, из-за стирания типа, в качестве времени выполнения у вас всегда есть Matcher<Object>. Так что в любом случае поведение во время выполнения одинаково.