У меня довольно сложный случай с дженериками и перегрузкой методов. Посмотрите этот примерный класс:
public class Test {
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public void test() {
// This works perfectly. <T> is bound to String
// ambiguity between setValue(.., String) and setValue(.., Field)
// is impossible as String and Field are incompatible
Parameter<String> p1 = getP1();
Field<String> f1 = getF1();
setValue(p1, f1);
// This causes issues. <T> is bound to Object
// ambiguity between setValue(.., Object) and setValue(.., Field)
// is possible as Object and Field are compatible
Parameter<Object> p2 = getP2();
Field<Object> f2 = getF2();
setValue(p2, f2);
}
private Parameter<String> getP1() {...}
private Parameter<Object> getP2() {...}
private Field<String> getF1() {...}
private Field<Object> getF2() {...}
}
Приведенный выше пример отлично компилируется в Eclipse (Java 1.6), но не с помощью команды Ant javac (или с помощью команды javac JDK), где я получаю это сообщение об ошибке при втором вызове setValue
:
ссылка на setValue неоднозначна, оба метода SetValue (org.jooq.Parameter, Т) в тесте и методе SetValue (org.jooq.Parameter, org.jooq.Field) в тестовом матче
В соответствии со спецификацией и моим пониманием того, как работает Java-компилятор, всегда следует выбирать наиболее специфический метод: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#20448
В любом случае, даже если <T>
привязан к Object
, что делает приемлемыми кандидаты для вызова setValue
приемлемыми кандидатами для вызова, параметр с параметром Field
всегда кажется более конкретным. И он работает в Eclipse, только не с компилятором JDK.
UPDATE
Подобным образом, он будет работать как в Eclipse, так и с помощью JDK-компилятора (конечно, с предупреждениями типа rawtypes). Я понимаю, что правила, указанные в спецификации, весьма специфичны, когда задействованы дженерики. Но я нахожу это довольно запутанным:
public <T> void setValue(Parameter<T> parameter, Object value) {
}
// Here, it easy to see that this method is more specific
public <T> void setValue(Parameter<T> parameter, Field value) {
}
ОБНОВЛЕНИЕ 2:
Даже с generics, я могу создать это обходное решение, где я избегаю привязки типа <T>
к Object
при времени setValue
, добавив дополнительную однозначную косвенность, называемую setValue0
. Это заставляет меня думать, что привязка T
к Object
действительно вызывает все проблемы здесь:
public <T> void setValue(Parameter<T> parameter, T value) {
}
public <T> void setValue(Parameter<T> parameter, Field<T> value) {
}
public <T> void setValue0(Parameter<T> parameter, Field<T> value) {
// This call wasn't ambiguous in Java 7
// It is now ambiguous in Java 8!
setValue(parameter, value);
}
public void test() {
Parameter<Object> p2 = p2();
Field<Object> f2 = f2();
setValue0(p2, f2);
}
Я что-то не понимаю? Есть ли известная ошибка компилятора, связанная с этим? Или есть способ обхода/компиляции, чтобы помочь мне?
Follow-Up:
Для тех, кто заинтересован, я подал отчет об ошибках как в Oracle, так и в Eclipse. Oracle приняла ошибку, пока Eclipse проанализировал ее и отклонил! Похоже, что моя интуиция правильная, и это ошибка в javac