인터페이스를 이용한 다형성
: 인터페이스도 구현 클래스의 부모? yes
인터페이스 타입 매개변수는 인터페이스 구현한 클래스의 객체만 가능 ( 외울 정도로 반복하기 )
interface Fightable {
void move(int x, int y);
void attack(Fightable f); // Fightable 을 구현한 클래스의 인스턴스만 가능
}
다중 상속의 문제
- 충돌 발생 : 같은 메서드가 있을 경우 어떤 것을 물려받을지 충돌
- 인터페이스는 구현부가 없기 때문에 충돌 안남.
인터페이스를 메서드의 리턴타입으로 지정할 수 있다.
// Fightable 인터페이스를 구현한 클래스를 반환한다는 의미
Fightable method(){
Fighter f = new Fighter();
return f;
// return new Fighter(); 한 문장으로 줄이면 다음과 같다.
}
class Fighter extends Unit implement Fightable{
public void move(int x, int y){/* 생략 */};
public void attack(Fightable f){/* 생략 */};
}
- 다형성 때문에 fighter 객체 반환 가능
- 메서드의 반환 타입이 인터페이스면 이 인터페이스를 구현한 객체를 리턴해야한다.
[정리]
- 메서드의 반환 타입이 인터페이스일 경우, 반환타입은 인터페이스를 구현한 객체를 반환해야한다.
- 메서드를 호출한 쪽에서는 반환타입과 일치하거나 자동형변환이 가능한 타입의 변수에 결과를 저장해야한다.
예제
인터페이스와 추상 클래스 선언
interface Fightable1 {
void move(int x, int y);
void attack(Fightable1 f);
}
abstract class Unit2 {
int x, y;
abstract void move(int x, int y);
void stop() {
System.out.println("멈춥니다.");
}
}
- Fightable1은 move, attack 메서드를 갖고
- Unit2 는 move, stop 메서드를 갖는다.
Fighter 클래스 생성 후 Unit2 를 상속받고, Fightable1 을 구현한다.
class Fighter extends Unit2 implements Fightable1 {
@Override
public void move(int x, int y) {
System.out.println("[ " + x + ", " + y + " ] 로 이동");
}
@Override
public void attack(Fightable1 f) {
System.out.println(f.toString() + "를 공격합니다. ");
}
}
- move, attack 메서드를 오버라이딩한다.
- move 메서드는 추상 클래스인 Unit 애도 있고, 인터페이스인 Fightable 에도 존재하는 메서드이지만 인터페이스의 둘 다 구현부가 없고 선언부만 있는 추상 메서드였기 때문에 충돌이 일어나지 않고 오버라이딩이 되는 걸 발견할 수 있다. (인터페이스의 다중 상속이 가능한 이유)
- 오버라이딩 조건 : 조상의 접근 제어 범위보다 좁으면 안된다.
- 인터페이스의 추상 메서드의 접근 제어자는 모두 public 이기 때문에 오버라이딩 한 메서드의 접근 제어자도 public 이어야 한다.
인스턴스 생성 후 호출해보기
public class FighterTest {
public static void main(String[] args) {
Fighter f = new Fighter();
f.move(100, 200);
f.attack(f);
Fightable1 f2 = new Fighter();
f2.move(1000, 2000); // Fightable1 인터페이스에는 stop() 메서드가 없기 때문에 호출 불가능
f2.attack(f2);
Unit2 u = new Fighter();
u.move(100,300);
u.stop(); // Unit 클래스에는 attack 메서드가 없기때문에 호출 불가능
}
}
이렇게 main 메서드에서 각각의 인스턴스 생성 후 호출을 해보면 다음과 같다.
- Fighter 클래스의 인스턴스 생성 후
- Fightable1 인터페이스를 참조변수 타입으로 설정 후 인스턴스 생성
- 해당 인터페이스에만 존재하는 메서드 호출 가능
- Unit2 추상 클래스를 참조 변수 타입으로 설정 후 인스턴스 생성
- 해당 추상 클래스에만 존재하는 메서드 호출 가능
- 즉, 참조변수를 생성 할 때 참조변수 타입이 리모콘 기능을 한다고 생각하면 편함.
- Unit2 의 리모콘으로 객체를 생성하면 당연히 Unit2 에만 있는 기능을 사용할 수 있다고 생각하자.
인터페이스의 다중 구현을 허용한다.
'👩💻 BackEnd > ☕️ 자바 [Java]' 카테고리의 다른 글
[Java] 자바의 정석 : 디폴트 메서드와 static 메서드 (0) | 2024.02.27 |
---|---|
[Java] 자바의 정석 : 인터페이스의 장점 (0) | 2024.02.27 |
[Java] 자바의 정석 : 인터페이스 (0) | 2024.02.26 |
[Java] 자바의 정석 : 추상 클래스와 추상 메서드 (0) | 2024.02.26 |
[Java] 자바의 정석 : 매개변수의 다형성 (0) | 2024.02.26 |