위의 사진과 같이 Class B와 C가 A를 상속받고, D가 B와 C를 상속받는 경우 A에서 상속받은 함수 또는 변수들을 B와 C에서 오버라이딩한다면,
D에서 이를 출력하였을 때 어떠한 값이 출력되는지에 대한 문제이다.
다이아몬드의 모양과 비슷한 구조이기 때문에 Diamond Problem이라고 명명되었다.
위의 문제를 Java로 구현한다면 다음과 같다.
public class A {
public void printHello() {
System.out.println("Hello from Class A");
}
}
public class B extends A{
public void printHello() {
System.out.println("Hello from Class B");
}
}
public class C extends A{
public void printHello() {
System.out.println("Hello from Class C");
}
}
public class D extends B, C {
public static void main(String[] args) {
D d = new D();
d.printHello();
}
public void printHello() {
System.out.println("Hello from Class D");
}
}
위의 예제의 경우 'Class cannot extend multiple classes'라는 에러가 발생한다. 그 이유는 Java는 Class의 다중상속을 허용하지 않기 때문이다.
그렇다면 Java는 어떻게 Diamond Problem을 해결하였을까?
Java의 경우 Diamond Problem을 Interface와 default method를 사용하여 해결하였다.
public interface A {
public default void printHello() {
System.out.println("Hello from Class A");
}
}
public interface B extends A{
public default void printHello() {
System.out.println("Hello from Class B");
}
}
public interface C extends A{
public default void printHello() {
System.out.println("Hello from Class C");
}
}
public class D implements B, C {
public static void main(String[] args) {
D d = new D();
d.printHello();
}
public void printHello() {
B.super.printHello(); // 상속을 받는 인터페이스의 이름으로 default method를 명시적으로 재정의해야 한다.
}
}
// result : Hello from B
위의 예제와 같이 구현이 필요한 함수를 default method로 Interface A, B, C에서 정의하였고, 이를 D에서 다중 상속받았다. 그 후 printHello를 오버라이딩하여 어떤 인터페이스의 default method를 사용할 것인지 명시하여준다. Java는 Java 8이후로 인터페이스를 사용하여 Diamond Problem을 해결하였다.