Неоднозначный вызов метода Java с обобщениями
Java неоднозначный вызов метода в следующем примере:
public class Foo {
public <Y, X extends Y> void set(Path<Y> attribute, X value) {
...
}
public <Y> void set(Path<Y> attribute, Expression<? extends Y> value) {
...
}
}
Попробуйте вызвать 2-й метод
Foo foo = new Foo();
Path<Object> path = new Path<Object>();
foo.set(path, new Expression<Object>(value));
Внутри затмения ошибок нет. Но в командной строке ошибка компиляции:
error: reference to set is ambiguous
foo.set(path, new Expression<Object>(value));
^
both method <Y#1,X>set(Path<Y#1>,X) in Foo and method <Y#2>set(Path<Y#2>,Expression<? extends Y#2>) in Foo match
where Y#1,X,T,Y#2 are type-variables:
Y#1 extends Object declared in method <Y#1,X>set(Path<Y#1>,X)
X extends Y#1 declared in method <Y#1,X>set(Path<Y#1>,X)
T extends Object declared in class Foo
Y#2 extends Object declared in method <Y#2>set(Path<Y#2>,Expression<? extends Y#2>)
Как вызвать 2-й метод?
1 ответ
Невозможно заставить компилятор выбрать любую версию метода. Как указано в комментариях, было бы целесообразно рассмотреть простой вызов обоих методов по-разному.
Возможно, вам следует рассмотреть возможность определения одного метода, который следует за более сложным Expression
подход и, когда необходимо, определить выражения, которые просто возвращают заданное постоянное значение.
Я думаю, что вы должны рассмотреть возможность использования лямбда или Supplier<X>
поддержать эти выражения:
public <X> void set(Path<X>, Supplier<? extends X> expression) {
// ...
X value = expression.get();
// ...
}
Затем:
final Path1<Integer> daysInAWeek = ...;
final Path2<Date> today = ...;
foo.set(daysInAWeek, () -> 7); // the constant value returning expression.
foo.set(today, () -> Date.todaysDate()); // calculated when invoked.
Каждый из тех foo.set
строки кода неявно объявляют внутренний класс, который расширяет Supplier
, Вы также можете создавать именованные классы верхнего уровня, которые реализуют Supplier
и передать экземпляр в качестве второго параметра в set
,
Также, если вы настаиваете на том, чтобы иметь свой собственный Expression
интерфейс / класс, который находится до тех пор, пока он квалифицируется как функциональный интерфейс, такой как Supplier
,