java8 interface의 변화(default method, static method)

java8에서 interface의 문법이 약간 변경되어 그 내용을 정리하고자 한다. java7 까지는 인터페이스에 상수, 실행블록이 없는 추상 메소드 선언만 가능했다. 하지만 java8부터 인터페이스에 디폴트메소드와 정적메소드도 추가로 선언이 가능하다. 이로인해 java의 인터페이스는 더욱 유연해진 코딩을 할 수 있다.

java8의 인터페이스 형태

1
2
3
4
5
6
7
8
9
10
interface 인터페이스명{
//상수
타입 상수명 = 값;
//추상 메소드
타입 메소드명(매개변수, ...);
//디폴트 메소드
default 타입 메소드명(매개변수, ...){ ... }
//정적 메소드
static 타입 메소드명(매개변수){ ...}
}

자바8에서 인터페이스의 디폴트메소드와 추상메소드가 추가된 이유가 있다. 어떤 프로그램에서 인터페이스 A가 있고 이 인터페이스를 구현한 A1, A2, A3..., A10 총 10개의 구현 클래스가 있다고 가정하자. 5년정도 사융하다가 인터페이스 A에 추가기능이 필요해서 추상메소드를 한개 추가하고 새로이 B1이라는 클래스로 인터페이스 A를 구현하게 된다. 문제는 기존에 사용하던 A1 ~ A10의 구현객체에서 B1클래스를 위해 추가된 추상메소드를 추가로 구현해야 한다는 점이다. java8에서는 인터페이스의 디폴트 메소드와, 정적메소드를 추가하여 프로그래밍의 유연성을 높여주고 있다.


인터페이스의 디폴트메소드(default method)

디폴트 메소드는 인터페이스에 선언되지만 사실은 객체(구현객체)가 가지고 있는 인스턴스 메소드라고 생각해야 된다. 따라서 인터페이스를 구현한 객체를 통해서 호출 해야만 한다. 자바8에서 디폴트 메소드를 허용한 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서이다. 만약 구현객체에서 인터페이스의 디폴트메소드가 적절하지 못하다면, 오버라이딩 하여 수정해서 사용하면 된다.

형태 : [public] default 리턴타입 메소드명(매개변수, ...){ ... }

인터페이스의 정적메소드(static method)

정적 메소드도 역시 자바8 부터 작성할 수 있는데, 디폴트 메소드와는 달리 객체가 없어도 인터페이스만으로 호출이 가능하다.

형태 : [public] static 리턴타입 메소드명(매개변수, ...){ ... }

java8의 인터페이스의 디폴트메소드, 추상메소드 예제

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
interface Java8InterfaceTest{

int talkCnt = 0;

void run();
//디폴트 메소드
default void talk(String msg){

if(msg != null && msg.equals("")){
System.out.println(msg);
}else{
System.out.println("난 디폴트 메소드다!");
}

}// talk
//정적 메소드
static void talk2(String msg){
if(msg != null && msg.equals("")){
System.out.println(msg);
}else{
System.out.println("난 정적 메소드다!");
}

}// talk2
}

public class InterfaceTest1 {

public static void main(String[] args) {

Java8InterfaceTest.talk2(null); // 정적메소드 호출

Java8InterfaceTest test1 = new Java8InterfaceTest(){

@Override
public void run() {
System.out.println("달려라!");
}

};

test1.run();
test1.talk(null); // 디폴트 메소드 호출

}

}

실행결과

1
2
3
난 정적 메소드다!
달려라!
난 디폴트 메소드다!


인터페이스의 상속에서 디폴트메소드의 변화

인터페이스는 인터페이스를 상속 할 수 있다. 자식 인터페이스에서 부모의 인터페이스를 상속할 때, 부모의 디폴트 메소드를 어떻게 할지 선택 할 수있다.

  1. 부모 인터페이스의 디폴트 메소드를 그냥 상속한다.

  2. 부모 인터페이스의 디폴트 메소드를 재정의(Override)한다.

  3. 부모 인터페이스의 디폴트 메소드를 추상메소드로 재 선언한다.

인터페이스의 디폴트메소드는 인터페이스의 강제성을 조금 유연하게 해주는 기능이다. 하지만 좋게 말하면 유연이고 나쁘게 말한다면 느슨한 것이다. 만약 이 느슨한것을 다시 엄격하게 수정할 필요가 있다면 인터페이스를 상속하여 다시 추상메소드로 재 선언 하는것도 방법이다. 개인적으로 java8의 인터페이스의 변화는 개발자의 자유도를 높여주는 기능처럼 보이며, 상당히 마음에 든다.


인터페이스 상수 선언(public static final)할 때 주의할점

java8의 특징은 아니지만, 자주 햇갈리는 부분이라 추가로 기록한다. 일반적인 클래스에서 상수(static final)의 초기화는 선언과 동시 그리고 정적영역(static block) 두 곳 모두에서 가능하다. 하지만 인터페이스의 상수는 정적영역(static block)에서 초기화 할수 없기 때문에 반드시 선언과 동시에 초기화 해야 한다.