TIL

인터페이스

류정근 2024. 4. 29. 20:47
인터페이스!!! 조금이라도 이해해보자!!!

 

인터페이스

자바는 순수 추상 클래스(모든 메서드가 추상인 클래스) 를 더 편리하게 사용 할 수있는 인터페이스라는 기능을 제공한다.

● 인터페이스의 메서드는 모두 `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()`이 호출된다.

 

출처 : 김영한의 실전 자바 - 기본편

'TIL' 카테고리의 다른 글

예외처리하기  (0) 2024.05.01
상속과 오버라이딩(Overriding)  (1) 2024.04.30
추상클래스  (0) 2024.04.27
상속 정복하기  (0) 2024.04.27
계산기 만들기  (3) 2024.04.26