Что такое модификатор default для методов в интерфейсах Java?

«Что такое модификатор default для методов в интерфейсах Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

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

Синтаксис и пример:

interface Vehicle {
    // Обычный абстрактный метод
    String getBrand();

    // Метод по умолчанию - имеет реализацию
    default String startEngine() {
        return "Engine of " + getBrand() + " started.";
    }

    // Статический метод в интерфейсе (также с Java 8)
    static void honk() {
        System.out.println("Beep!");
    }
}

class Car implements Vehicle {
    @Override
    public String getBrand() {
        return "Toyota";
    }
    // Метод startEngine() НЕ ОБЯЗАТЕЛЬНО переопределять,
    // будет использована реализация по умолчанию.
}

// Использование
Car myCar = new Car();
System.out.println(myCar.startEngine()); // "Engine of Toyota started."
Vehicle.honk(); // Вызов статического метода

Ключевые правила и особенности:

  1. Не обязателен для переопределения: Классы, реализующие интерфейс, могут использовать реализацию по умолчанию, не переопределяя метод.
  2. Конфликт при множественном наследовании: Если класс реализует два интерфейса с одинаковыми default-методами, возникает неоднозначность. Класс обязан явно переопределить этот метод.
    interface A { default void foo() { System.out.println("A"); } }
    interface B { default void foo() { System.out.println("B"); } }
    class C implements A, B {
        @Override
        public void foo() {
            // Можно выбрать одну из реализаций или предоставить свою
            A.super.foo(); // Явный вызов реализации из интерфейса A
        }
    }
  3. Не могут переопределять методы Object: Интерфейс не может объявить default-метод для equals, hashCode или toString.
  4. Модификаторы доступа: default-методы неявно public. Их нельзя сделать private, protected или static (для static есть отдельный вид методов).
  5. Отличие от абстрактных классов: Интерфейс с default-методами всё ещё не может иметь состояния (полей экземпляра), в отличие от абстрактного класса.

Типичное применение: Добавление удобных методов-утилит в интерфейсы коллекций (например, sort() в List<E>), что позволило улучшить API, не требуя изменений в миллионах строк существующего кода.