Почему компиляция Java 8 завершается неудачно, когда метод по умолчанию переопределяется статическим методом подкласса? - PullRequest
2 голосов
/ 25 мая 2019

Принимая во внимание Java 8, почему приведенный ниже код не скомпилируется?

interface Father {
    static void method() { }
}

interface Mother {
    default void method() { }
}

interface Child extends Father, Mother {
    static void method() { }
}

Насколько я понимаю, каждый статический метод принадлежит своему определенному классу, поэтому, почему, когда дочерний интерфейс определяет static void method() { }, компилятор выдает следующую ошибку?

method () в Child конфликтует с method () в методе переопределения Mother - статический

Не должен ли Child сохранять реализацию метода по умолчанию от Mother при разрешении Father and Child ссвои собственные статические методы, такие как: Father.method () и Child.method ()?

Ответы [ 3 ]

4 голосов
/ 25 мая 2019

Father здесь не проблема, поскольку статические методы от интерфейсов не наследуются (например, List.of(..) не может быть вызвано через ArrayList.of(..)), поэтому существует нет переопределения / скрытия, что также означает отсутствие столкновений.

Из-за этого мы можем смело писать

interface Father {
    static void method() { } 
}
interface Child extends Father {
    static void method() { } 
}

Проблема - это метод default void method() { } из интерфейса Mother, который наследуется Child, что означает, что после

interface Child extends Father, Mother { 
    static void method() { } 
}

В итоге вы получите интерфейс, который будет иметь две версии method(): статическую и нестатическую (по умолчанию)

interface Child extends Father, Mother { 
    static void method() { } 
    default void method() { } //inherited from Mother
}

Но почему это проблема?

Представьте, что вы хотите добавить еще один метод в интерфейс Child, который будет вызывать method()

interface Child extends Father, Mother { 
    static void method() { } 
    default void method() { } //inherited from Mother
    default void demo(){
        method(); //which code block should be executed?
    }
}

Должен ли он выполнять код из static method () или из default method ()? Компилятор не сможет решить.

Хотя эту ситуацию можно решить с помощью

  • Child.method() для статического метода,
  • this.method() для метода по умолчанию (да, он не будет неоднозначным, потому что статический метод не будет наследоваться классом, экземпляр которого this будет экземпляром),

Дело в том, чтобы предотвратить подобные проблемы в первую очередь. Вот почему мы должны не иметь статических и нестатических методов с одинаковыми сигнатурами (name + parameterTypes) в одном месте (определенном или унаследованном).

1 голос
/ 25 мая 2019

Это интересная ситуация. Я думаю, что простой ответ заключается в том, что статическим методам никогда не разрешалось скрывать (они не могут переопределять) нестатические методы в базовых классах. Если вы удалите модификатор static из Father, это также приведет к тому, что Child не будет компилироваться. Это, вероятно, чтобы избежать путаницы.

Таким образом, методы по умолчанию просто следовали этому существующему правилу.

«Но подождите», как вы могли подумать, «методы по умолчанию были добавлены с явным намерением позволить разработчикам библиотек вводить новые функциональные возможности в старые интерфейсы, не нарушая существующий код. Если какой-либо существующий код имеет статический метод с конфликтующим именем - не сломается ли? "

На самом деле я думаю, что нет. IIRC, это место, где бинарная совместимость и совместимость с источниками преднамеренно могут отличаться. Я думаю, что вы найдете это, если:

  • interface Child (и все, что с его помощью) уже скомпилировано, хотя этот метод по умолчанию отсутствовал в interface Mother и
  • вы позже добавили метод по умолчанию к interface Mother и скомпилировали только этот исходный файл.

Тогда я думаю, что вы получите код, работающий просто отлично (на уровне байт-кода / JVM). Однако во время компиляции он сломался бы в момент, когда вы пытались перекомпилировать interface Child против обновленного interface Mother.

0 голосов
/ 02 июня 2019

Я также нашел это Oracle Tutorial , который объясняет больше случаев.

В основном здесь вы можете найти резюме (извлеченное из учебника):

Defining a Method with the Same Signature as a Superclass's Method

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