Как интерфейс решает проблему ромба в Java?

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

    interface A {
        default void func() {
            System.out.println("A");
        }
    }
    
    interface B {
        default void func() {
            System.out.println("B");
        }
    }
    class C implements A, B {
        @Override
        public void func() {
            A.super.func();
            B.super.func();
            System.out.println("C");
        }
    }
    public class Main {
        public static void main(String[] args) {
            C obj = new C();
            obj.func();
        }
    }

    interface A {
        default void foo() {
            System.out.println("A");
        }
    }
    
    interface B extends A {
        default void foo() {
            System.out.println("B");
        }
    }
    
    class C implements A, B {
        public static void main(String[] args) {
            new C().foo();
        }
    }

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


Ответы (2 шт):

Автор решения: talex

У тебя неправильный пример проблемы ромба.

Вот корректный:

public class App {
    public static void main(String[] args) {
        new D().foo();
    }

    interface A {
        default void foo() {
            System.out.println("A.foo");
        }
    }

    interface AB extends A {
        default void foo() {
            System.out.println("AB.foo");
        }
    }

    interface AC extends A {
        default void foo() {
            System.out.println("AC.foo");
        }
    }

    static class D implements AB, AC {
    }
}

И он выдает ошибку:

App.java:27:12
java: types App.AB and App.AC are incompatible;
  class App.D inherits unrelated defaults for foo() from types App.AB and App.AC
→ Ссылка
Автор решения: Евгений Тупиков

Default методы были придуманы для других задач. Вот выдержка из документации:

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces. Полное описание...

Про множественное наследование можно почитать тут

Если в двух словах, то интерфейсы не хранят состояния.

→ Ссылка