인터페이스에선 추상 메소드를 빼고 디폴트 메소드도 존재한다.
디폴트 메소드는 인터페이스에서 바로 사용할 수 없고 또한, 추상 메소드가 아닌 인스턴스 메소드이므로 구현 객체가 있어야 사용할 수 있다.
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 | interface RemoteControlIn { //상수 int MAX_VOLUME = 10; int MIN_VOLUME = 0; //추상 메소드 void turnOn(); void turnOff(); void setVolume(int volume); //디폴트 메소드 default void setMute(boolean mute) { if(mute) { System.out.println("무음 처리합니다"); } else { System.out.println("무음 해제합니다."); } } //정적 메소드 static void chanegeBattery() { System.out.println("건전지를 교환합니다."); } } Colored by Color Scripter |
디폴트 메소드는 setMute(boolean mute)인데 이 메소드는 바깥에서
RemoteControlIn.setMute(true)와 같이 접근이 불가능하다.
RemotecontrolIn의 객체를 생성해야 접근이 가능하다.
이 디폴트 메소드도 오버라이딩이 가능해서 구현 클래스가 자신에 맞게 오버라이딩하면 재정의한 메소드가 호출된다.
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 | class Television implements RemoteControlIn { private int volume; public void turnOn() { //turnOn 추상메소드 실체 메소드(오버라이딩) System.out.println("TV를 켭니다."); } public void turnOff() { //turnOff 추상 메소드 오버라이딩 System.out.println("TV를 끕니다"); } public void setVolume(int volume) { //setVolume 메소드 오버라이딩 if(volume > RemoteControlIn.MAX_VOLUME) { this.volume = RemoteControlIn.MAX_VOLUME; //최대 크기가 넘지 않도록 설정 } else if(volume < RemoteControlIn.MIN_VOLUME) { this.volume = RemoteControlIn.MIN_VOLUME; //최소 크기가 넘지 않도록 설정 } else { this.volume = volume; } System.out.println("현재 TV 볼륨 "+volume); } } Colored by Color Scripter |
위는 setVolume을 오버라이딩한 것을 보여준다.
이후
RemoteControlIn rc = new Television();
rc.turnOn();
rc.setMute(true);
와 같이 사용할 수 있다.
정적 메소드는
RemoteControl.changeBattery();와 같이 접근이 가능하다. static이므로.
인터페이스 또한 상속처럼 다형성과 타입 변환이 존재한다. 이 부분은 상속가 내용이 겹치므로 생략한다.
인터페이스는 다른 인터페이스를 상속할 수 있다. 인터페이스는 클래스와는 달리 다중 상속을 허용한다.
하위 인터페이스를 구현하는 클래스는 하위 인터페이스의 메소드뿐만 아니라 상위 인터페이스의 모든 추상 메소드에 대한 실체 메소드를 가지고 있어야 한다.
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 | interface InterfaceA{ public void methodA(); } interface InterfaceB{ public void methodB(); } interface InterfaceC extends InterfaceA, InterfaceB{ public void methodC(); } class ImpleEx implements InterfaceC { public void methodA() { } public void methodB() { } public void methodC() { } } Colored by Color Scripter |
하위 인터페이스를 상속하는 구현 클래스는 상위 인터페이스 내용까지 다 작성해야 한다.
그럼 디폴트 메소도는 도대체 왜 쓰이는지 알아보자
디폴트 메소드는 왜 쓰일까?
인터페이스에서 디폴트 메소드를 허용한 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서이다. 기존 인터페이스의 잉름과 추상 메소드의 변경 없이 디폴트 메소드만 추가할 수 있기 때문에 이전에 개발한 구현 클래스를 그대로 사용하면서 새롭게 개발하는 클래스는 디폴트 메소드를 활용할 수 있다.
만약 InterfaceA에 추후 시간이 흘러 method3()이 추가 되었다고 하자. 만약 이 메소드가 추상 메소드라면 InterfaceA를 구현한 클래스는 구현하지 않았기에 에러가 나올 것이다. 하지만 디폴트 메소드로 추가할 경우엔 구현 클래스에선 에러가 뜨지 않는다. 추상 메소드가 아니기 때문에!
'java' 카테고리의 다른 글
자바 중첩 인터페이스, 익명 인터페이스(익명 객체) (0) | 2017.08.17 |
---|---|
중첩 클래스, 내부 클래스(inner class, nested class), 로컬 클래스 (0) | 2017.08.16 |
자바 인터페이스 - 1 (0) | 2017.08.16 |
자바 추상 클래스, 추상 메소드, 자동 타입 변환 (0) | 2017.08.16 |
자바 instanceof (0) | 2017.08.16 |