JDK прав.2-й метод не более специфичен, чем 1-й.Из JLS3 # 15.12.2.5
"Неформальная интуиция заключается в том, что один метод более специфичен, чем другой, если любой вызов , обрабатываемый первым методом, может быть передан другому без компиляцииошибка типа. "
Это явно не тот случай.Я подчеркнул любой вызов .Свойство одного метода более специфично, чем другого, зависит исключительно от самих двух методов;он не меняется при каждом вызове.
Формальный анализ вашей проблемы: м2 более конкретен, чем m1?
m1: <R> void setValue(Parameter<R> parameter, R value)
m2: <V> void setValue(Parameter<V> parameter, Field<V> value)
Во-первых, компилятору необходимо вывести R из начальных ограничений:
Parameter<V> << Parameter<R>
Field<V> << R
Результат равен R=V
, согласно правилам вывода в 15.12.2.7
Теперь мы подставляем R
и проверяем отношения подтипов
Parameter<V> <: Parameter<V>
Field<V> <: V
Вторая строка делаетне выполняется согласно правилам подтипов в 4.10.2.Таким образом, m2 не более конкретен, чем m1.
V
не является Object
в этом анализе;анализ учитывает все возможные значения V
.
. Я бы предложил использовать разные имена методов.Перегрузка никогда не является необходимостью.
Это, похоже, серьезная ошибка в Eclipse.Спецификация довольно ясно указывает, что переменные типа не заменяются на этом шаге.Eclipse, очевидно, сначала выполняет подстановку переменных типа, , а затем проверяет отношение специфичности метода.
Если такое поведение более «разумно» в некоторых примерах, то в других это не так.Скажем,
m1: <T extends Object> void check(List<T> list, T obj) { print("1"); }
m2: <T extends Number> void check(List<T> list, T num) { print("2"); }
void test()
check( new ArrayList<Integer>(), new Integer(0) );
«Интуитивно», и формально в соответствии со спецификацией, м2 более специфичен, чем m1, и тест выдает «2».Однако, если замена T=Integer
выполняется первой, оба метода становятся идентичными!
для обновления 2
m1: <R> void setValue(Parameter<R> parameter, R value)
m2: <V> void setValue(Parameter<V> parameter, Field<V> value)
m3: <T> void setValue2(Parameter<T> parameter, Field<T> value)
s4: setValue(parameter, value)
Здесь m1 не применяетсядля вызова метода s4, поэтому m2 является единственным выбором.
В соответствии с 15.12.2.2, чтобы увидеть, применимо ли m1 для s4, сначала выполняется вывод типа, чтобы сделать вывод, что R = T;затем мы проверяем Ai :< Si
, что приводит к Field<T> <: T
, что неверно.
Это согласуется с предыдущим анализом - если m1 применимо к s4, то любой вызов обрабатывается m2 (по сути, такой же, как s4) может обрабатываться m1, что означает, что m2 будет более точным, чем m1, что неверно.
в параметризованном типе
Рассмотрим следующий код
class PF<T>
{
public void setValue(Parameter<T> parameter, T value) {
}
public void setValue(Parameter<T> parameter, Field<T> value) {
}
}
void test()
PF<Object> pf2 = null;
Parameter<Object> p2 = getP2();
Field<Object> f2 = getF2();
pf2.setValue(p2,f2);
Компилируется без проблем.Согласно 4.5.2, типы методов в PF<Object>
являются методами в PF<T>
с подстановкой T=Object
.То есть методы pf2
являются
public void setValue(Parameter<Object> parameter, Object value)
public void setValue(Parameter<Object> parameter, Field<Object> value)
2-й метод более специфичен, чем 1-й.