이것이 자바다 의 Chapter08 을 참고하여 정리한 포스트입니다.

이전글
인터페이스 이론정리 - 1
인터페이스 이론정리 - 2
인터페이스 이론정리 - 3
인터페이스 이론정리 - 4
인터페이스 이론정리 - 5

Chapter 08. 인터페이스 - (6)

7. 디폴트 메소드와 인터페이스 확장

디폴트 메소드 : 인터페이스에 선언된 인스턴스 메소드이므로 구현 객체가 있어야 사용 가능하다.

  • 선언은 인터페이스, 사용은 구현 객체를 통해 한다.


7.1 디폴트 메소드의 필요성

인터페이스에서 디폴트 메소드를 허용한 이유
  • 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서다
  • 기존 인터페이스의 이름과 추상 메소드 변경 없이 디폴트 메소드만 추가 가능함
  • 윗 줄의 이유로 이전에 개발한 구현 클래스를 그대로 사용하면서 새롭게 개발하는 클래스로 디폴트 메소드를 활용 가능

ex) 디폴트 메소드가 필요한 경우

  • 기존 MyInterface 인터페이스
  • 이를 구현한 MyClassA 클래스의 method1() 메소드
  • 위의 구성에서 기능을 추가하려고 MyInterface 에 추상 메소드를 추가하면 MyClassA에서 문제가 발생한다.

  • 예시 오류 이유
    • 추가된 추상 메소드에 대한 실체 메소드가 MyClassA 에 없기 때문이다.
  • 디폴트 메소드 추가로 오류 해결
    • MyInterface 에 디폴트 메소드를 선언한다.
    • 디폴트 메소드는 추상 메소드가 아니기 때문에 구현 클래스에서 실체 메소드를 작성할 필요가 없다. (MyClassA 사용 가능)
  • 수정한 MyInterface 를 구현한 새로운 MyClassB 구현 클래스는 method1() 내용은 반드시 채워야 한다.
  • MyClassB 구현 클래스에서 디폴트 메소드인 method1() 는 MyInterface 에 정의된 것을 사용하거나 재정의해서 사용할 수 있다.

  • MyInterface.java 기존 인터페이스
    1
    2
    3
    
    public interface MyInterface {
      public void method1();
    }
    
  • MyClassA.java 기존 구현 클래스
    1
    2
    3
    4
    5
    6
    
    public class MyClassA implements MyInterface {
      @Override
      public void method1() {
        System.out.println("MyClassA-method1() 실행");
      }
    }
    
  • MyInterface.java 수정 인터페이스
    1
    2
    3
    4
    5
    6
    7
    8
    
    public interface MyInterface {
      public void method1();
        
      // 디폴트 메소드 추가
      public default void method1() {
        System.out.println("MyInterface-method2() 실행");
      }
    }
    

    인터페이스를 수정해도 MyClassA 는 컴파일 에러가 발생하지 않는다.

  • MyClassB 새로운 구현 클래스
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    public class MyClassB implement MyInterface {
      @Override
      public void method1() {
        System.out.println("MyClassB-method1() 실행");
      }
    
      //디폴트 메소드 재정의
      @Override
      public void method2() {
        System.out.println("MyClassB-method2() 실행");
      }
    }
    
  • DefaultMethodExample.java 디폴트 메소드 사용
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    public class DefaultMethodExample {
      public static void main(String[] args) {
        MyInterface mi1 = new MyClassA();
        mi1.method1();
        mi1.method2();
    
        MyInterface mi2 = new MyClassB();
        mi2.method1();
        mi2.method2();
      }
    }
    
    실행결과
    MyClass-method1() 실행
    MyInterface-method2() 실행
    MyClassB-method1() 실행
    MyClassB-method2() 실행
    • MyClassA 의 method2() 는 MyInterface 에 정의된 디폴트 메소드가 실행되었다.

7.1 디폴트 메소드가 있는 인터페이스 상속

부모 인터페이스에 디폴트 메소드가 정의되어 있을 때 자식 인터페이스에서 디폴트 메소드 활용 방법

  • 디폴트 메소드를 단순히 상속만 받는다.
  • 디폴트 메소드를 재정의(Overrid) 해서 실행 내용을 변경한다.
  • 디폴트 메소드를 추상 메소드로 재선언한다.
ex) 인터페이스 메소드 호출

추상 메소드와 디폴트 메소드가 선언된 ParentInterface 와 자식 인터페이스들이 구성된다고 가정한다.

  • ParentInterface.java 부모 인터페이스
    1
    2
    3
    4
    5
    6
    
    public interface ParentInterface {
      public void method1();
      public default void method2() { 
        System.out.println("ParentInterface-method2 실행");
      }
    }
    


  • ChildInterface1.java 자식 인터페이스
    1
    2
    3
    4
    
    public interface ChildInterface1 extends ParentInterface {
      //자식 인터페이스의 추상 메소드 method3() 선언
      public void method3();
    }
    

    이럴 경우 ChildInterface 인터페이스를 구현하는 클래스는 method1()과 method3() 의 실체 메소드를 가지고 있어야 한다.
    ParentInterface 의 method2() 를 호출할 수 있다.

  • Implementation1.java 구현 클래스
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    public class Implementation1 {
      public static void main(String[] args) {
        
      ChildInterface1 ci1 = new ChildInterface1() {
      @Override
      public void method1() {
        System.out.println("Implementation1-method1 실행");
      }
    
      @Override
      public void method3() {
        System.out.println("Implementation1-method3 실행");
      }
      };
        
      ci1.method1();
      ci1.method2();  //ParentInterface 의 method2() 호출
      ci1.method3();
      
      }
    }
    
    실행 결과
    Implementation1-method1 실행
    ParentInterface-method2 실행
    Implementation1-method3 실행


  • ChildInterface2.java 자식 인터페이스
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    public interface ChildInterface2 extends ParentInterface {
      @Override
      //디폴트 메소드 method2() 재정의
      public default void method2() {
        System.out.println("ChildInterface2-method2 실행");
      } 
      //자신의 추상 메소드로 선언
      public void method3();
    }
    

    이 경우도 ChildInterface2 인터페이스를 구현하는 클래스는 method1(), method3() 의 실체 메소드를 가져야 한다.
    ChildInterface2 에서 재정의한 method2() 를 호출할 수 있다.

  • Implementation2.java 구현 클래스
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    public class Implementation2 {
      public static void main(String[] args) {
        
        ChildInterface2 ci2 = new ChildInterface2() {
        @Override
        public void method1() {
          System.out.println("Implementation2-method1 실행");
        }
        @Override
        public void method3() {
          System.out.println("Implementation2-method3 실행");
        }
        };
        
      ci2.method1();
      ci2.method2(); //ChildInterface2 의 method2() 호출
      ci2.method3();
        
      }
    }
    
    실행결과
    Implementation2-method1 실행
    ChildInterface2-method2 실행
    Implementation2-method3 실행


  • ChildInterface3.java 자식 인터페이스
    1
    2
    3
    4
    5
    6
    7
    
    public interface ChildInterface3 extends ParentInterface {
      @Override
      //디폴트 메소드 method2() 를 추상 메소드로 재선언
      public void method2();  
      //자신의 추상 메소드로 선언
      public void method3();  
    }
    

    이 경우에는 ChildInterface3 인터페이스를 구현 클래스는 method1(), method2(), method3() 의 실체 메소드를 모두 가지고 있어야 한다.

  • Implementation3.java 구현 클래스

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    //ChildInterface3 인터페이스 구현 클래스
    public class Implementation {
      public static void main(String[] args) {
    
        ChildInterface3 ci3 = new ChildInterface3() {
        @Override
        public void method1() {
          System.out.println("Implementation3-method1 실행");
        }
        @Override
        public void method2() {
          System.out.println("Implementation3-method2 실행");
        }
        @Override
        public void method3() {
          System.out.println("Implementation3-method3 실행");
        }
        };
    
        ci3.method1();
        ci3.method2(); //ChildInterface3 구현 객체의 method2() 호출
        ci3.method3();
    
      }
    }
    
    실행결과
    Implementation3-method1 실행
    Implementation3-method2 실행
    Implementation3-method3 실행

🌞 정보 : 공부 기록용 블로그입니다. 오타나 내용 오류가 있을 경우 알려주시면 감사하겠습니다.

댓글남기기