Неоднозначный вызов метода 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,

Другие вопросы по тегам