Как реализовать множественное наследование поведения в Java?

«Как реализовать множественное наследование поведения в Java?» — вопрос из категории ООП, который задают на 23% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Java не поддерживает множественное наследование классов для избежания проблемы "ромбовидного наследования" (неоднозначность вызова метода, если он определён в двух родительских классах).

Однако, начиная с Java 8, можно эмулировать множественное наследование поведения с помощью интерфейсов с default-методами.

Пример и решение конфликта:

interface Logger {
    default void log(String message) {
        System.out.println("LOG[" + getClass().getSimpleName() + "]: " + message);
    }
}

interface Serializer {
    default void log(String message) { // Конфликт имён!
        System.out.println("Serialization log: " + message);
    }
    String serialize();
}

// Класс ДОЛЖЕН явно разрешить конфликт
class DataProcessor implements Logger, Serializer {
    private String data;

    // Способ 1: Предоставить свою реализацию
    @Override
    public void log(String message) {
        System.out.println("DataProcessor: " + message);
    }

    // Способ 2: Делегировать вызов конкретному интерфейсу
    public void logAsSerializer(String msg) {
        Serializer.super.log(msg); // Явный вызов реализации из Serializer
    }

    @Override
    public String serialize() { return "Processed: " + data; }
}

Важные ограничения:

  1. Наследуется только поведение (методы), но не состояние (поля). Интерфейсы могут содержать только static final константы.
  2. Класс-наследник обязан переопределить метод, если у него есть конфликтующие default-реализации из нескольких интерфейсов.
  3. Приоритет: реализация в классе > default-метод в интерфейсе.

Альтернатива: Композиция. Часто композиция (включение объектов с нужным поведением) предпочтительнее сложной иерархии интерфейсов.

class DataProcessor {
    private Logger logger = new ConsoleLogger();
    private Serializer serializer = new JsonSerializer();

    void process() {
        logger.log("Start");
        String result = serializer.serialize();
        logger.log("Result: " + result);
    }
}