자바8 - 인터페이스 default 메소드와 static 메소드

현시기얌·2021년 8월 27일
0

JAVA8

목록 보기
7/8

인터페이스의 기본 메소드

- 인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법

- 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있다.

ex)

public interface GreetingInterface {
    void printName();
public class DefaultGreeting implements GreetingInterface{
    @Override
    public void printName() {
        System.out.println("Greeting");
    }
}

GreetingInterface를 구현한 DefaultGreeting 클래스가 있다고 가정하면 DefaultGreeting 클래스는 GreetingInterface가 선언한 메소드를 구현해야 한다.
그런데 나중에 아래와 같이 GreetingInterface를 구현할 때 공통적으로 제공해줬으면 하는 기능을 추가 하고 싶다면??

Interface에 printNameUpperCase() 기능 추가

public interface GreetingInterface {
    void printName();
    void printNameUpperCase();
}

Class

public class DefaultGreeting implements GreetingInterface{
    @Override
    public void printName() {
        System.out.println("Greeting");
    }
    @Override
    public void printNameUpperCase() {
        System.out.println("GREETING");
    }
}

위와 같이 GreetingInterface를 구현한 모든 클래스는 컴파일 에러가 발생하면서 printNameUpperCase()를 구현하라고 나온다.
하지만 아래와 같이 Interface 메소드에 default를 추가해서 직접 구현해주면

public interface GreetingInterface {
    void printName();
    default void printNameUpperCase(){
        System.out.println("GREETING");
    }
}
public class DefaultGreeting implements GreetingInterface{
    @Override
    public void printName() {
        System.out.println("Greeting");
    }
}

해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있다.

- 기본 메소드는 구현체가 모르게 추가된 기능으로 그만큼 리스크가 있다.

  • 컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생할 수 있다. (ex name이 null인 경우)
  • 반드시 문서화 할 것 (@ImplSpec 자바독 태그 사용)
public interface GreetingInterface {
    void printName();
    /**
     * @ImplSpec 이 구현체는 getName()으로 가져온 문자열을 대문자로 바꿔 출력한다.
     */
    default void printNameUpperCase(){
        System.out.println(getName().toUpperCase());
    } 
    String getName();
}

- Object가 제공하는 기능 (equals, hashCode)는 기본 메소드로 제공할 수 없다.

  • 구현체가 재정의해야 한다.

- 본인이 수정할 수 있는 인터페이스에만 기본 메소드를 제공할 수 있다.

- 인터페이스를 상속받는 인터페이스에서 다시 추상 메소드로 변경할 수 있다.

public interface GreetingInterface {
    void printName();
    /**
     * @ImplSpec 이 구현체는 getName()으로 가져온 문자열을 대문자로 바꿔 출력한다.
     */
    default void printNameUpperCase(){
        System.out.println(getName().toUpperCase());
    }
    String getName();
}
public interface HelloInterface extends GreetingInterface{
    void printNameUpperCase();
}

GreetingInterface를 상속받는 HelloInterface는 printNameUpperCase()를 다시 재정의 할 수 있는데 이렇게 재정의를 하게되면
HelloInterface를 구현한 구현체들은 printNameUpperCase()를 다시 구현해야 한다.

- 인터페이스 구현체가 재정의 할 수도 있다.

public interface GreetingInterface {
    void printName();
    /**
     * @ImplSpec 이 구현체는 getName()으로 가져온 문자열을 대문자로 바꿔 출력한다.
     */
    default void printNameUpperCase(){
        System.out.println(getName().toUpperCase());
    }
    String getName();
}
public class DefaultGreeting implements GreetingInterface{
    private String name;
    public DefaultGreeting(String name) {
        this.name = name;
    }
    @Override
    public void printName() {
        System.out.println(this.name);
    }
    @Override
    public void printNameUpperCase() {
        System.out.println(this.name.toUpperCase());
    }
    @Override
    public String getName() {
        return name;
    }
}

위와 같이 Interface에서 구현된 default 메소드를 구현체에서 다시 재정의 할 수 있다.

- 참고

public interface GreetingInterface {
    void printName();
    /**
     * @ImplSpec 이 구현체는 getName()으로 가져온 문자열을 대문자로 바꿔 출력한다.
     */
    default void printNameUpperCase(){
        System.out.println(getName().toUpperCase());
    }
    String getName();
}
public interface HelloInterface {
    default void printNameUpperCase() {
        System.out.println("HELLO");
    }
}
public class DefaultGreeting implements GreetingInterface, HelloInterface{
    private String name;
    public DefaultGreeting(String name) {
        this.name = name;
    }
    @Override
    public void printName() {
        System.out.println(this.name);
    }
    @Override
    public String getName() {
        return name;
    }
}

만약 이름이 같은 default 메소드가 있는 인터페이스 2개를 동시에 구현할려고 하면 어떤 인터페이스의 default 메소드를 구현해야 할지 모르기 때문에 컴파일 에러가 발생한다.

인터페이스의 스태틱 메소드

public interface GoodByeInterface {
    static void printAnything() {
        System.out.println("GoodBye");
    }
}
    public static void main(String[] args) {
        GoodByeInterface.printAnything();
    }
  • 해당 타입 관련 헬퍼 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.
profile
현시깁니다

0개의 댓글

관련 채용 정보