Метод по умолчанию добавляет очень хорошую новую функцию к набору инструкций JVM. После использования метода по умолчанию, если новый метод добавляется в интерфейс в библиотеке, пользовательский класс, который реализует этот интерфейс, может автоматически получить реализацию этого метода по умолчанию. Как только пользователь хочет обновить свой класс реализации, просто переопределите этот метод по умолчанию и замените его реализацией, которая делает более значимой в определенном сценарии. Что еще лучше, так это то, что пользователи могут вызвать реализацию интерфейса по умолчанию в переписываемом методе, чтобы добавить некоторые дополнительные функции.
Пока все довольно хорошо. Однако добавление методов по умолчанию к существующим интерфейсам Java может привести к несовместимости кода . Это легко понять, глядя на пример. Предположим, существует библиотека, которая требует, чтобы пользователь реализовал один из своих интерфейсов в качестве ввода:
интерфейс SimpleInput {void foo (); void bar ();} абстрактный класс SimpleInputAdapter реализует SimpleInput {@Override public void bar () {// некоторое поведение по умолчанию ...}}Перед Java 8 комбинация вышеуказанного интерфейса и соответствующего класса адаптера была очень распространенной шаблоном на языке Java. Разработчики библиотеки классов предоставляют адаптер для сокращения количества кодировки для библиотечных потребителей. Тем не менее, цель предоставления этого интерфейса на самом деле состоит в том, чтобы достичь взаимосвязи, аналогичной множеству наследования.
Давайте предположим, что пользователь использует этот адаптер:
класс myInput Extens SimpleInputAdapter {@Override public void foo () {// что -то ...} @Override public void bar () {super.bar (); // Сделай что -нибудь дополнительно ...}}С помощью этой реализации пользователи могут взаимодействовать с библиотекой. Обратите внимание, как эта реализация переопределяет метод стержня, чтобы добавить дополнительную функциональность в реализацию по умолчанию.
Так что же произойдет, если эта библиотека перенесена на Java 8? Прежде всего, эта библиотека, вероятно, отбросит класс адаптера и перенесет эту функцию на метод по умолчанию. В конце концов, этот интерфейс будет выглядеть так:
интерфейс SimpleInput {void foo (); по умолчанию void bar () {// некоторое поведение по умолчанию}}}С помощью этого нового интерфейса пользователь должен обновить свой код, чтобы использовать этот метод по умолчанию вместо класса адаптера. Одним из замечательных преимуществ использования нового интерфейса вместо класса адаптера является то, что пользователи могут наследовать другой класс вместо этого класса адаптера. Давайте начнем с практики и преобразовываете класс MyInput в использование метода по умолчанию. Поскольку теперь мы можем наследовать другие классы, мы постараемся продлить дополнительный сторонний базовый класс. То, что делает этот базовый класс, здесь не важно. Давайте предположим, что это имеет смысл для нашего варианта использования.
Класс myInput расширяет третьипартибазекс, реализует simpleInput {@Override public void foo () {// что -то сделать ...} @Override public void bar () {simpleInput.super.foo (); // Сделай что -нибудь дополнительно ...}}Чтобы достичь той же функции, что и исходный класс, мы использовали новый синтаксис Java 8, чтобы вызвать методы по умолчанию интерфейса. Точно так же мы помещаем логику Mymethod в базовый класс Mybase. Вы можете расслабиться после удара плечами. Это было потрясающе после рефакторинга!
Эта библиотека, которую мы используем, была значительно улучшена. Тем не менее, обслуживающий персонал должен добавить еще один интерфейс для реализации некоторых дополнительных функций. Этот интерфейс называется Compexinput, который наследует класс SimpleInput и добавляет дополнительный метод. Поскольку обычно считается, что метод по умолчанию может быть добавлен с уверенностью, персонал обслуживания переопределял метод по умолчанию класса SimpleInput и добавил некоторые дополнительные действия, чтобы предоставить пользователю лучшую реализацию по умолчанию. В конце концов, это очень распространено при использовании классов адаптеров:
интерфейсный комплекс INPUT Extends SimpleInput {void qux (); @Override по умолчанию void bar () {simpleInput.super.bar (); // так сложно, нам нужно сделать больше ...}}Эта новая функция выглядит очень хорошей, поэтому сопровождающий третьего класса частибасекалса также решил использовать эту библиотеку. Чтобы достичь этого, он внедрил третий паразитный класс в интерфейс ComplexInput.
Но что это значит для класса MyInput? Поскольку он наследует третий класс партизабазекалса, интерфейс ComplexInput реализуется по умолчанию. Таким образом, вызов метода SimpleInput по умолчанию не является законным. Результатом является то, что код пользователя не может быть составлен в конце. Кроме того, этот метод совершенно невозможно, потому что Java считает этот супер-супер-метод, чтобы назвать косвенным родительским классом незаконным. Вы можете вызвать только метод по умолчанию интерфейса комплекса. Тем не менее, это сначала требует, чтобы вы явно реализовали этот интерфейс в классе MyInput. Для пользователей этой библиотеки эти изменения совершенно неожиданно.
(Примечание: просто выразить это, это на самом деле:
Интерфейс a {по умолчанию void test () {}} интерфейс B расширяет {по умолчанию void test () {}} тест открытого класса реализует b {public void test () {b.super.test (); //A.super.test (); Ошибка }}Конечно, если вы напишете это, пользователь активно решил реализовать интерфейс B. Пример в статье представил базовый класс, поэтому в библиотеке и базовом классе было сделано, что в библиотеке и базовом классе было внесено нетратенциальное изменение, но на самом деле это привело к тому, что код пользователя не смог быть составлена)
Как ни странно, Java не различает это во время выполнения. Валидатор JVM позволяет скомпилированному классу для вызова метода SimpleInput :: Foo, хотя загруженный класс наследует обновленную версию ThirdPartyBaseClass и неявно реализует интерфейс ComplexInput. Если вы хотите винить, вы можете только обвинить компилятор. (ПРИМЕЧАНИЕ: Компилятор и поведение во время выполнения противоречивы)
Так что мы узнали из этого? Проще говоря, не переопределяйте метод по умолчанию исходного интерфейса в другом интерфейсе. Не переписывайте его с другим методом по умолчанию и не переписывайте его с помощью некоторого абстрактного метода. Короче говоря, вы должны быть очень осторожны при использовании метода по умолчанию. Несмотря на то, что они облегчают интерфейсы существующих библиотек сбора Java, это позволяет вам делать вызовы методов в структуре наследования класса, что по существу увеличивает сложность. Перед Java 7 вам просто нужно было пройти линейную иерархию классов и посмотреть на фактический код вызова. Когда вы чувствуете, что вам действительно нужно, используйте метод по умолчанию.
Выше приведено подробное объяснение того, почему вы должны использовать метод по умолчанию Java 8 с осторожностью. Я надеюсь, что это будет полезно для каждого обучения.