Какова цель ключевого слова по умолчанию в Java?


95

Интерфейс в Java похож на класс, но тело интерфейса может включать только абстрактные методы и finalполя (константы).

Недавно я увидел вопрос, который выглядит так

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

Согласно определению интерфейса, разрешены только абстрактные методы . Почему это позволяет мне скомпилировать приведенный выше код? Какое defaultключевое слово?

С другой стороны, когда я пытался написать код ниже, он говорит modifier default not allowed here

default class MyClass{

}

вместо того

class MyClass {

}

Может ли кто-нибудь сказать мне цель defaultключевого слова? Разрешено ли это только внутри интерфейса? Чем он отличается от default(без модификатора доступа)?


4
методы по умолчанию в интерфейсах были добавлены в Java 8. Это не модификатор доступа, это реализация по умолчанию.
Эран

2
@Eran вам не кажется, что введение метода по умолчанию нарушает определение интерфейса? : s
Рави

2
Это изменило определение интерфейса. Это определение устарело.
Луи Вассерман,

2
Они были введены для поддержки лямбда-выражений. Подробная информация о том, почему они необходимы, содержится в предложении соломенного человека для проекта Lambda.
спринтер

Ответы:


75

Это новая функция в Java 8, которая позволяет interfaceпредоставлять реализацию. Описан в Java 8 JLS-13.5.6. Объявления метода интерфейса, который читает (частично)

Добавление defaultметода или изменение метода с abstractна defaultне нарушает совместимость с уже существующими двоичными файлами, но может вызвать ошибку, IncompatibleClassChangeErrorесли уже существующий двоичный файл пытается вызвать метод. Эта ошибка возникает, если квалифицирующий тип Tявляется подтипом двух интерфейсов Iи J, где оба Iи Jобъявляют defaultметод с той же сигнатурой и результатом, и ни один из них Iне Jявляется подинтерфейсом другого.

Что нового в JDK 8 говорит (частично)

Методы по умолчанию позволяют добавлять новые функции в интерфейсы библиотек и обеспечивать двоичную совместимость с кодом, написанным для более старых версий этих интерфейсов.


16
Кажется, теперь интерфейс и абстрактный класс практически совпадают. :)
Рави

16
Интерфейсы @jWeaver по-прежнему не могут иметь конструкторов, полей, частных методов или реализаций equals / hashCode / toString.
Луи Вассерман

10
@ Луис Вассерман: В Java 9 у них могут быть privateметоды.
Holger

6
@Dan Pantry: privateметоды на самом деле не являются частью интерфейса, но могут служить вспомогательными методами для defaultреализаций или внутри постоянных инициализаторов. Обратите внимание, что они уже существуют в Java 8, так как при использовании лямбда-выражений в интерфейсах privateсоздаются синтетические методы. Таким образом, Java 9 позволяет вам использовать эту функцию также для несинтетических, не лямбда-выражений…
Holger

14
@jWeaver Разница между интерфейсами и классами сводится к состоянию и поведению . Интерфейсы могут нести поведение, но только классы могут иметь состояние. (Поля, конструкторы и методы, такие как equals / hashCode, относятся к состоянию.)
Брайан Гетц,

26

Методы по умолчанию были добавлены в Java 8 в первую очередь для поддержки лямбда-выражений. Дизайнеры (на мой взгляд, хитроумно) решили создать синтаксис лямбда-выражений для создания анонимных реализаций интерфейса. Но учитывая, что лямбды могут реализовывать только один метод, они будут ограничены интерфейсами с одним методом, что было бы довольно серьезным ограничением. Вместо этого были добавлены методы по умолчанию, позволяющие использовать более сложные интерфейсы.

Если вам нужно какое-то убедительное утверждение, которое defaultбыло введено из-за лямбда-выражений, обратите внимание, что в предложении соломенного человека проекта Lambda, сделанном Марком Рейнхольдом в 2009 году, «методы расширения» упоминаются как обязательная функция, которая должна быть добавлена ​​для поддержки лямбда-выражений.

Вот пример, демонстрирующий концепцию:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

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


8
Это не совсем правильно. Лямбды могут быть непосредственной причиной, но на самом деле они были лишь той соломинкой, которая сломала спину верблюду. Настоящая мотивация заключалась в том, чтобы позволить эволюцию интерфейса (позволяя существующим интерфейсам развиваться совместимо для поддержки нового поведения); лямбда-выражения могли быть фактором, который выдвинул эту потребность на передний план, но эта функция носит более общий характер.
Брайан Гетц,

@BrianGoetz: ИМХО, и Java, и .NET получили бы огромную выгоду, если бы с самого начала существовали методы по умолчанию. Если какая-то обычная операция может быть выполнена в любой реализации интерфейса с использованием только членов интерфейса, но некоторые реализации, вероятно, будут иметь более эффективный способ их выполнения, интерфейс должен определять методы для этих операций и предоставлять для них реализации по умолчанию. Невозможность указать реализации по умолчанию вызвала давление, чтобы интерфейсы не использовали такие методы, и сделало невозможным их добавление позже.
supercat

@BrianGoetz Я согласен с тем, что методы по умолчанию имеют большую ценность, чем лямбды. Но я был бы заинтересован в любых ссылках, которые вы могли бы дать об этом более широком значении, побудившем вас включить их. Я считаю, что лямбды были основной причиной (именно поэтому в своем ответе я использовал слово «в первую очередь»).
спринтер

2
Возможно, вам поможет этот документ: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html . В разделе 10 четко сказано: «Назначение методов по умолчанию (ранее называвшихся методами виртуального расширения или методами защитника) состоит в том, чтобы позволить интерфейсам развиваться совместимым образом после их первоначальной публикации». Затем в качестве иллюстрации эволюции интерфейса цитируются методы, дружественные к лямбда .
Brian Goetz

2
@Kartik Вы задаете неправильный вопрос! Мы не выбираем синтаксис, основанный на том, «какой абсолютный минимум необходим компилятору для правильного анализа программы»; мы выбираем его на основании того, «что намерения программиста будут более очевидными для читателей». Мы проектируем в первую очередь для пользователей, а во вторую - для компиляторов (а когда дело касается пользователей, мы проектируем в первую очередь для чтения, а во вторую - для написания)
Брайан Гетц

16

В Java 8 представлена ​​новая концепция, называемая методами по умолчанию. Методы по умолчанию - это те методы, которые имеют некоторую реализацию по умолчанию и помогают в развитии интерфейсов без нарушения существующего кода. Давайте посмотрим на пример:

 public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

 class SimpleInterfaceImpl implements SimpleInterface{

  @Override
  public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Not required to override to provide an implementation
  * for doSomeOtherWork.
  */

 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

и вывод:

Реализация
DoSomeOtherWork в классе DoSomeOtherWork в интерфейсе


16

В других ответах не учитывалась его роль в аннотациях. Еще в Java 1.5 defaultключевое слово появилось как средство для предоставления значения по умолчанию для поля аннотации.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

Его использование было перегружено с появлением Java 8, чтобы можно было определять метод по умолчанию в интерфейсах.

Еще кое-что было упущено: причина того, что объявление default class MyClass {}недействительно, связана с тем, как классы вообще объявляются . В языке нет положения, позволяющего использовать это ключевое слово. Однако он появляется для объявлений методов интерфейса .


3

Новая функция Java 8 ( методы по умолчанию ) позволяет интерфейсу предоставлять реализацию, если она помечена defaultключевым словом.

Например:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

Тест интерфейса использует ключевое слово default, которое позволяет интерфейсу предоставлять реализацию метода по умолчанию без необходимости реализации этих методов в классах, использующих интерфейс.

Обратная совместимость: представьте, что ваш интерфейс реализован сотнями классов, изменение этого интерфейса заставит всех пользователей реализовать недавно добавленный метод, даже если он не является существенным для многих других классов, реализующих ваш интерфейс.

Факты и ограничения:

1-Может быть объявлен только в интерфейсе, а не в классе или абстрактном классе.

2-Должен предоставить тело

3-Он не считается общедоступным или абстрактным, как другие обычные методы, используемые в интерфейсе.


3

Методы по умолчанию в интерфейсе позволяют нам добавлять новые функции, не нарушая старый код.

До Java 8, если новый метод был добавлен к интерфейсу, тогда все классы реализации этого интерфейса были обязаны переопределить этот новый метод, даже если они не использовали новую функциональность.

В Java 8 мы можем добавить реализацию по умолчанию для нового метода, используя defaultключевое слово перед реализацией метода.

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

пример

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }

2

Очень хорошее объяснение можно найти в The Java ™ Tutorials , часть объяснения выглядит следующим образом:

Рассмотрим пример, в котором участвуют производители автомобилей с компьютерным управлением, которые публикуют стандартные отраслевые интерфейсы, описывающие, какие методы можно использовать для управления их автомобилями. Что, если эти производители автомобилей с компьютерным управлением добавят в свои машины новые функции, такие как полет? Этим производителям необходимо будет указать новые методы, которые позволят другим компаниям (например, производителям электронных приборов наведения) адаптировать свое программное обеспечение для летающих автомобилей. Где эти производители автомобилей объявят эти новые методы, связанные с полетами? Если они добавят их к своим исходным интерфейсам, программистам, которые реализовали эти интерфейсы, придется переписать свои реализации. Если они добавят их как статические методы, тогда программисты будут рассматривать их как служебные методы, а не как важные базовые методы.

Методы по умолчанию позволяют добавлять новые функции к интерфейсам ваших библиотек и обеспечивать двоичную совместимость с кодом, написанным для более старых версий этих интерфейсов.


1

Методы по умолчанию позволяют добавлять новые функции в интерфейсы ваших приложений. Его также можно использовать для множественного наследования . В дополнение к методам по умолчанию вы можете определять статические методы в интерфейсах. Это упрощает организацию вспомогательных методов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.