«Неверная» реализация универсального метода: почему я не получаю ошибку компиляции? - PullRequest
7 голосов
/ 29 октября 2019

У меня есть интерфейс, содержащий метод с такой сигнатурой:

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

По сути, MergeProperty - это класс, который НЕ реализует RestartApplicant и RestartApplicant это функциональный интерфейс, содержащий метод, который на самом деле не имеет значения для понимания этой проблемы.

Здесь есть подвох. Когда я создаю класс, реализующий этот интерфейс, Java позволяет мне запускать без какой-либо ошибки компиляции следующий код:

public class MyImplementation implements MyInterfacePreviouslyDescribed {

    @Override
    public List<MergeProperty<MathObject>> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }
}

Очевидно, я не уважаю ограничения реализации там,Учитывая эту подпись, список, который я возвращаю, используя Arrays.asList(...), действительно НЕ должен содержать элементы, которые реализуют RestartApplicant. Помните, MergeProperty не реализует RestartApplicant. Так что это, скорее всего, приведет к ошибке где-то.

Тем не менее, я получаю предупреждение:

Type safety: The return type List<Main.MergeProperty<Main.MathObject>> for
loadPropertiesFrom(Main.MathObject, Main.MathObject) (...) needs unchecked
conversion to conform to List<Main.MergeProperty&Main.RestartApplicant> from the
type Main.Test<Main.MathObject>

Мой вопрос: почему я получаю только предупреждение? Мне кажется, что я не должен быть в состоянии скомпилировать мой код. Есть ли какая-то особая причина для этого?

Заранее спасибо.

РЕДАКТИРОВАТЬ

Поработав немного с моим кодом, я подумал, что если япереместил «объявление обобщения» на уровень класса, что привело бы к:

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant>

вместо

interface MyInterfacePreviouslyDescribed<T>

и, очевидно,

List<P> loadPropertiesFrom(T p1, T p2);

вместо

<P extends MergeProperty<T> & RestartApplicant> List<P> loadPropertiesFrom(T p1, T p2);

тогда я на самом деле получу ошибку компиляции, если попробую ту же "нелегальную" реализацию, что и раньше. Это кажется еще более странным ...

1 Ответ

2 голосов
/ 29 октября 2019

Вы даже можете сделать:

    @Override
    public List<String> loadPropertiesFrom(MathObject p1, MathObject p2) {
        return Arrays.asList(
            // some random instances of MergeProperty that do not implement RestartApplicant
        );
    }

в первом случае. Это связано с тем, что переопределенный метод не универсальный и стирание для них будет List. Почему это разрешено? Честно говоря, я не знаю, может быть, это связано с обратной совместимостью.

Во втором примере кажется, что это действительно должно быть:

interface MyInterfacePreviouslyDescribed<T, P extends MergeProperty<T> & RestartApplicant> {

и в реализации, которую вы заставляететипы должны быть правильными. На самом деле, второй пример интуитивно понятен - он не компилируется;и что является ожидаемым. Первый, с другой стороны, использует некое правило совместимости для неуниверсальных методов, которое позволяет переопределить одно и то же стирание.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...