본문으로 바로가기

1. 디폴트 메소드

[public] default 리턴타입 메소드명(매개변수, ...) { 
    // ... (실행 내용)
}
  • 자바 8부터 인터페이스에 디폴트 메소드가 추가되었습니다.
  • 인터페이스에 선언된 인스턴스 메소드이기 때문에 구현 객체가 있어야 사용할 수 있습니다.
  • 선언은 인터페이스에서 하고, 사용은 구현 객체를 통해 사용합니다.
  • 구현 클래스에서 오버라이딩을 통해 해당 구현체에 맞게 수정이 가능합니다.

 

2. 디폴트 메소드의 필요성

기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서입니다.

기존 인터페이스의 이름과 추상 메소드의 변경 없이 디폴트 메소드만 추가할 수 있기 때문에 

이전에 개발한 구현 클래스를 그대로 사용할 수 있으면서 새롭게 개발하는 클래스는 디폴트 메소드를 활용할 수 있습니다.

 

추상 메소드로 기능 추가하면 되지 않나요?

인터페이스에 추상 메소드를 추가적으로 작성할 경우에는

해당 인터페이스를 구현하는 구현 클래스에 추가적으로 추상 메소드에 대해 실체 메소드를 작성해야 합니다. 

 

인터페이스를 구현하는 클래스가 적거나 혹은 수정할 여건이 될 경우에는 

구현 클래스에서 추가적으로 작성을 하면 되지만 (하지 않을 경우 에러 발생)

 

구현 클래스를 수정할 여건이 안될 경우에는 인터페이스의 확장이 불가능해집니다. 

 

예시

public interface A {
    void methodA();
    void methodA2(); // 기능 확장을 위해 추상 메소드 선언
}
// 에러 발생) AImpl is not abstract and does not override abstract method methodA2()
public class AImpl implements A {
    @Override
    public void methodA() {
        System.out.println("method A");
    }
}

 

자바 8 디폴트 메소드의 등장

자바 8부터는 디폴트 메소드가 추가되면서

기능을 확장하고자 한다면 인터페이스에 디폴트 메소드를 선언하면 됩니다.

디폴트 메소드는 정의되어있는 그대로 사용해도 되고, 필요에 따라 재정의해서 사용할 수도 있습니다.

 

예시

public interface A {
    void methodA();

    // 디폴트 메소드
    default void methodDefaultA() {
        System.out.println("Default method A");
    }
}
public class AImpl implements A {
    @Override
    public void methodA() {
        System.out.println("method A");
    }

    // 오버라이딩을 통해 구현체에 맞게 수정도 가능합니다.
//    @Override
//    public void methodDefaultA() {
//        System.out.println("오버라이딩");
//    }
}

 

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

부모 인터페이스에 디폴트 메소드가 정의되어 있을 경우, 자식 인터페이스에서 디폴트 메소드를 활용하는 방법 세 가지

1) 디폴트 메소드를 단순히 상속만 받는다.

2) 디폴트 메소드를 재정의해서 실행 내용을 변경합니다.

3) 디폴트 메소드를 추상 메소드로 재 선언합니다.

 

1) 디폴트 메소드를 단순히 상속만 받는다.

public interface A {
    void methodA();

    // 디폴트 메소드
    default void methodDefaultA() {
        System.out.println("Default method A");
    }
}
public interface B extends A {
    void methodB();
}
public class BImpl implements B {
    @Override
    public void methodA() {
        System.out.println("method A");
    }

    @Override
    public void methodB() {
        System.out.println("method B");
    }
}
B b = new BImpl();
b.methodA(); // method A
b.methodB(); // method B
b.methodDefaultA(); // Default method A

 

2) 디폴트 메소드를 재정의해서 실행 내용을 변경합니다.

public interface B extends A {
    void methodB();

    // 디폴트 메소드 재정의
    @Override
    default void methodDefaultA() {
        // A.super.methodDefaultA();
        System.out.println("Default method B");
    }
}
B b = new BImpl();
b.methodA(); // method A
b.methodB(); // method B
b.methodDefaultA(); // Default method B

 

​3) 디폴트 메소드를 추상 메소드로 재 선언합니다.

public interface B extends A {
    void methodB();

    // 디폴트 메소드를 추상 메소드로 재선언
    void methodDefaultA();
}
public class BImpl implements B {
    @Override
    public void methodA() {
        System.out.println("method A");
    }

    @Override
    public void methodB() {
        System.out.println("method B");
    }

    // 디폴트 메소드 -> 추상 메소드 (실체 메소드 작성)
    @Override
    public void methodDefaultA() {
        System.out.println("Default method To abstract method");
    }
}
B b = new BImpl();
b.methodA(); // method A
b.methodB(); // method B
b.methodDefaultA(); // Default method To abstract method