Яка мета ключового слова за замовчуванням у Java?


94

Інтерфейс у 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.
спринтер

Відповіді:


74

Це нова функція в 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 дозволяє використовувати цю функцію для несинтетичного, не лямбда-використання ...
Холгер

14
@jWeaver Різниця між інтерфейсами та класами зводиться до стану проти поведінки . Інтерфейси можуть нести поведінку, але лише класи можуть мати стан. (Поля, конструктори та методи, такі як equals / hashCode, стосуються стану.)
Brian Goetz

26

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

Якщо вам потрібно переконатись у твердженні, яке defaultбуло представлено через лямбди, зауважте, що у пропозиції солом’яного проекту від проекту Лямбда Марка Рейнгольда в 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: IMHO, як 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 в інтерфейсі


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
}

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

Зворотна сумісність: Уявіть, що ваш інтерфейс реалізований сотнями класів, модифікація цього інтерфейсу змусить усіх користувачів застосувати нещодавно доданий метод, хоча це не є важливим для багатьох інших класів, що реалізують ваш інтерфейс.

Факти та обмеження:

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

Дуже гарне пояснення можна знайти у підручниках Java ™ , частина пояснення полягає в наступному:

Розглянемо приклад, у якому беруть участь виробники машин, керованих комп’ютером, які публікують стандартні в галузі інтерфейси, що описують, які методи можна використовувати для керування своїми автомобілями. Що робити, якщо ці комп'ютерно керовані виробники автомобілів додадуть до своїх автомобілів нові функції, такі як політ? Цим виробникам потрібно буде вказати нові методи, щоб дозволити іншим компаніям (наприклад, виробникам електронних приладів наведення) адаптувати своє програмне забезпечення до літаючих автомобілів. Де ці виробники автомобілів заявлять про нові методи, пов'язані з польотами? Якщо вони додають їх до своїх початкових інтерфейсів, тоді програмістам, які реалізували ці інтерфейси, доведеться переписати свої реалізації. Якщо вони додають їх як статичні методи, то програмісти розглядають їх як корисні методи, а не як основні, основні методи.

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


1

Методи за замовчуванням дозволяють додати нову функціональність до інтерфейсів ваших програм. Він також може бути використаний для отримання багатоспадкової спадщини . На додаток до методів за замовчуванням, ви можете визначати статичні методи в інтерфейсах. Це полегшує вам організацію допоміжних методів

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.