인터페이스의 default method와 다이아몬드 문제
Java

인터페이스의 default method와 다이아몬드 문제

1. 알고자 하는 것

- default method란 무엇인지

- 자바의 인터페이스에 default method가 고안된 이유는 무엇인지

- default method가 가능해짐에 따라 발생할 수 있는 다이아몬드 문제 (Diamond Problem)를 자바는 어떻게 해결하는지

 

2. 알게된 것

Default Method

- 원래 자바에서 인터페이스(Interface)에는 오직 상수와 추상 메서드만을 가질 수 있었다.

- 이로 인해 다음 사례와 같은 개발자들의 불편함이 생겼다.

1. A 인터페이스를 구현한 n개의 클래스가 있다.

2. 설계의 변경으로 A 인터페이스를 구현한 n개의 클래스에 대해 공통 메서드가 하나 추가되었다.

3. 이 때, A 인터페이스에 추상 메서드를 추가하고, n개의 클래스에 대해 추상 메서드를 구현해야 한다.

- 완벽한 설계라 할지라도 언제나 변경의 여지가 있다.

- 이러한 불편함을 해소하고자, 자바 8에 추상 메서드에 대해 기본 구현을 제공하는 default method를 제공한다.

 

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        InterfaceA a = new ClassA();
        a.method();
        a.defaultMethod();
    }

    static class ClassA implements InterfaceA {

        @Override
        public void method() {
            System.out.println("오버라이딩 필수");
        }

//        @Override
//        public void defaultMethod() {
//            오버라이딩 필수 아님
//        }
    }

    interface InterfaceA {
        // 기존
        void method();

        // default method
        default void defaultMethod() {
            System.out.println("추상 메서드에 대해 구현 가능");
        }
    }
}

 

다이아몬드 문제 (Diamond Problem)

- 이렇듯, 자바8에서부터 제공하는 Default Method로 인해 다이아몬드 문제가 발생할 수 있다.

- 다이아몬드 문제란, n개의 인터페이스를 상속 받았을 때, n개의 인터페이스에 동일한 메서드 시그니처를 가지는 메서드를 default method로 구현하고 있다면 자바의 다중상속 문제와 같이 어떠한 method가 호출될 지 결정할 수 없고 충돌하는 문제를 의미한다.

 

- 위와 같은 상속 구조에서 C.hello()를 호출했을 때, A 인터페이스가 구현한 hello(), B 인터페이스가 구현한 hello() 중 어떤것이 호출되어야 하는지 명확하지 않은 충돌이 발생한다.

- 이를 다이아몬드 문제라고 한다. 

- 이러한 문제를 막기위해 자바에서는 클래스의 다중상속을 지원하지 않는다.

 

자바에서 인터페이스 다중구현에 대한 다이아몬드 문제를 해결하는 규칙

1. 인터페이스의 default method보다 클래스의 method가 우선권을 가진다.

- 같은 메서드 시그니처를 가지는 메서드1(인터페이스 default method)와 메서드2(클래스 method)가 있을 때, 해당 클래스와 인터페이스를 상속받은 클래스에서 메서드를 호출할 때에는 메서드2(클래스 method)가 호출된다.

 

2. 1의 규칙이 적용되지 않는다면 서브 인터페이스의 default method가 우선권을 가진다. 

- 같은 메서드 시그니처를 가지는 메서드1(인터페이스1 default method)와 메서드2(인터페이스1을 상속받은 서브 인터페이스 default method)가 있을 때, 해당 인터페이스 1,2를 상속받은 클래스에서 메서드를 호출할 때에는 메서드2(서브 인터페이스 method)가 호출된다.

 

3. 1,2의 규칙이 적용되지 않는다면 명시적으로 충돌이 발생한 Default Method를 오버라이딩하여 호출한다.

- 1, 2의 규칙이 적용되지 않아 여전히 충돌이 발생할 때, 해당 메서드를 명시적으로 오버라이딩하라는 컴파일 오류가 발생한다.

- 클래스는 충돌이 발생한 해당 메서드를 오버라이딩하여 명시적으로 재정의해야한다.

- 이 때, InterfaceA.super.method()와 같이 명시적으로 어떤 default method를 호출할 지 정하여 호출이 가능하다.

 

 

3. 정리

- Default Method로 인해 인터페이스의 설계 변경에 대해 유연하게 코드를 변경할 수 있고, 변경점을 최소화 할 수 있다.

- 이로 인해 발생하는 다이아몬드 문제(다중 상속으로 발생 가능한 문제)를 자바에서는 위 서술한 3가지 규칙을 통해 방지한다.

 


Reference

자바와 다중상속 문제

Java 8 디폴트 메서드(Default Method) : 다이아몬드 문제(=다중 상속) 해결하기