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(); }
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(); }
- 해당 타입 관련 헬퍼 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.