인터페이스
인터페이스!!! 조금이라도 이해해보자!!!
인터페이스
자바는 순수 추상 클래스(모든 메서드가 추상인 클래스) 를 더 편리하게 사용 할 수있는 인터페이스라는 기능을 제공한다.
● 인터페이스의 메서드는 모두 `public` , `abstract` 이다. -> 굳이 적지않아도 자동으로 적용됨
●메서드에 `public abstract` 를 생략할 수 있다. 참고로 생략이 권장된다.
●인터페이스는 다중 구현(다중 상속)을 지원한다. --> 인터페이스의 존재이유
사용방법
public interface InterfaceAnimal {
void sound();
void move();
}
public abstract 키워드 생략이 가능하다.
인터페이스는 `class` 대신에 `interface` 로 선언하면 된다.
`sound()` , `move()` 는 앞에 `public abstract` 가 생략되어 있다. 따라서 상속 받는 곳에서 모든 메서드를 오버라
이딩 해야 한다.
인터페이스를 상속받을 때
public class Dog implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("멍멍");
}
@Override
public void move() {
System.out.println("개 이동");
}
}
인터페이스를 상속 받을 때는 `extends` 대신에 `implements` 라는 구현 이라는 키워드를 사용해야 한다. 인터페이스
는 그래서 상속이라 하지 않고 구현이라 한다.
인터페이스와 멤버 변수
public interface InterfaceAnimal {
double MY_PI = 3.14;
}
인터페이스에서 멤버 변수는 public, stact, final 이 모두 포함되었다고 간주된다.
--> ( public static final) double MY_PI = 3.14;
자바에서 `static final` 을 사용해 정적이면서 고칠 수 없는 변수를 상수라 하고, 관례상 상수는 대문자에 언더스코
어( _ )로 구분한다.
클래스 상속 관계는 UML에서 실선을 사용하지만, 인터페이스 구현(상속) 관계는 UML에서 점선을 사용한다.
인터페이스를 사용해야 하는 이유
●제약
인터 페이스를 만드는 이유는 인터페이스를 구현하는 곳에서 인터페이스의 메서드를 반드시 구현해라는 제약을 주는 것이다. 순수 추상 클래스의 경우 누군가 그곳에 실행 가능한 메서드를 끼워 넣을 수 있다. 이렇게 되면 더이상 순수 추상 클래스가 아니게 된다. 인터페이스는 이러한 문제를 원천 차단할 수 있다. (모든 메서드가 추상 메서드이기 때문)
●다중 구현
자바에서 클래스 상속은 부모를 하나만 지정할 수 있다. 반면에 인터페이스는 부모를 여러명 두는 다중 구현(다중 상속)이 가능하다.
다이아몬드 문제 ( 다중 상속이 안되서 생기는 문제)
만약 다중상속이 가능하여 비행기와 자동차를 상속받는 하늘을 나는 자동차를 만든다면, AirplaneCar` 입장에서 `move()` 를 호출할 때 어떤 부모의 `move()` 를 사용해야 할지 애매한 문제가 발생한다. 이것을 다이아몬드 문제라 한다
그리고 계층문제가 매우 복잡해 질 수 있기 때문에 자바는 클래스의 다중 상속을 허용하지 않는다.
인터페이스 다중 구현
`InterfaceA` , `InterfaceB` 는 둘다 같은 `methodCommon()` 을 가지고 있다. 그리고 `Child` 는 두 인터페이스를
구현했다. 상속 관계의 경우 두 부모 중에 어떤 한 부모의 `methodCommon()` 을 사용해야 할지 결정해야 하는 다이아
몬드 문제가 발생한다. 하지만 인터페이스는 자신은 구현을 가지지 않는다. (대신 인터페이스를 구현하는 곳에서 해당 기능을 모두 구현해야 한다.)
여기서 `InterfaceA` , `InterfaceB` 는 같은 이름의 `methodCommon()` 를 제공하지만 이것의 기능은 `Child`
가 구현한다. 그리고 오버라이딩에 의해 어차피 `Child` 에 있는 `methodCommon()` 이 호출된다. 결과적으로 두 부모
중에 어떤 한 부모의 `methodCommon()` 을 선택하는 것이 아니라 그냥 인터페이스들을 구현한 `Child` 에 있는
`methodCommon()` 이 사용된다. 이런 이유로 인터페이스는 다이아몬드 문제가 발생하지 않는다. 따라서 인터페이스
의 경우 다중 구현을 허용한다.
내가 이해한 것 : 다이아몬드 문제 그림에서는 자바에서는 다중상속을 허용하지 않는데 허용한다는 가정을 두었다.
하지만 일반 부모 클래스와 인터페이스의 차이점으로는 인터페이스에서는 모든 메서드가 추상 메서드이기 때문에
기능을 추가하더라도 하위 클래스에서 그 기능을 무조건 오버라이딩 하여 구현해야 한다. 하지만 일반 상속에서는
추상메서드가 아닌 일반메서드를 사용하여 기능을 추가하는게 가능하여 하위 클래스에서 없는 기능이 실행이 될 수
있고, 어디서 그 기능이 실행된지 찾기힘들어지고, 계층 구조가 복잡해질 수 있다.
인터페이스 다중 구현 예시
public interface InterfaceA {
void methodA();
void methodCommon();
}
public interface InterfaceB {
void methodB();
void methodCommon();
}
public class Child implements InterfaceA, InterfaceB {
@Override
public void methodA() {
System.out.println("Child.methodA");
}
@Override
public void methodB() {
System.out.println("Child.methodB");
}
@Override
public void methodCommon() {
System.out.println("Child.methodCommon");
}
}
//인터페이스 다중 구현
public class DiamondMain {
public static void main(String[] args) {
InterfaceA a = new Child();
a.methodA();
a.methodCommon();
InterfaceB b = new Child();
b.methodB();
b.methodCommon();
}
}
implements InterfaceA, InterfaceB` 와 같이 다중 구현을 할 수 있다. `implements` 키워드 위에 , 로 여러 인터페이스를 구분하면 된다.
`methodCommon()` 의 경우 양쪽 인터페이스에 다 있지만 같은 메서드이므로 구현은 하나만 하면 된다.
1. `a.methodCommon()` 을 호출하면 먼저 `x001` `Child` 인스턴스를 찾는다.
2. 변수 `a` 가 `InterfaceA` 타입이므로 해당 타입에서 `methodCommon()` 을 찾는다.
3. `methodCommon()` 은 하위 타입인 `Child` 에서 오버라이딩 되어 있다. 따라서 `Child` 의 `methodCommon()`이 호출된다.
4. `b.methodCommon()` 을 호출하면 먼저 `x001` `Child` 인스턴스를 찾는다.
5. 변수 `b` 가 `InterfaceB` 타입이므로 해당 타입에서 `methodCommon()` 을 찾는다.
6. `methodCommon()` 은 하위 타입인 `Child` 에서 오버라이딩 되어 있다. 따라서 `Child` 의 `methodCommon()`이 호출된다.
출처 : 김영한의 실전 자바 - 기본편