Zeolot : 땅 / 지상공격
Marine : 땅 / 공중공격
Zergling : 땅 / 지상공격
Wraith : 하늘 / 공중공격, 지상공격
날아다닌다는 속성을 부여할 것인데 이렇게 만들면 힘들다.
벤타이어그램 (아래로 갈수록 속해져있음)
Marine
--------------------
Unit
--------------------
object
Zealot
--------------------
Unit
--------------------
object
Wraith
------------------- → interface
// FlyingUnit
--------------------
Unit
--------------------
object
Wraith 유닛 추가 (marine / zeolot과의 차이는 Wraith는 날아다닌다.)
고조부모 증조부모 조부모 부모 자식인터페이스를 사용하면 위와같은 일렬적인 관계에서 특정한 친구를 뽑아서 속성을 줄 수 있다.
- 왜 상속관계를 안쓰나면 자식이 여러개의 부모를 가질 수 없어서 1:1관계이다. 그렇지만 인터페이스는 하나의 클래스에 여러개를 사용할 수 있다.
- Wraith라는 Terran 종족 소속인 유닛 한개 생성 (Unit 상속받는다.)
어떠한 유닛은 날아다닌다라는것을 명시해주기 위해 IFly인터페이스 생성하자.
: 클래스간 상속은 1:1 이기 때문에 어떠한 클래스에 속성을 부여하여 다형성을 보다 강화시키고자 사용함.
: 대문자
I+ 파스칼 케이스(주로 형용사), 혹은 그냥 파스칼 케이스(-able)
- 대문자
I는 인터페이스를 알리기위해 사용하는데 안쓰는 곳도 있다.
- 접근 제한자는 반드시
public. 생략해도public이며 기본적으로 생략한다.- 정적인 상수. 생략해도
static final이며 기본적으로 생략한다.- 멤버 변수는 반드시
public static final이다.
public static final붙이니 회색으로 변했다. 기본적으로 붙기 때문에 사용하지 않아도 된다는 의미이다.
접근제한자는 반드시
public, 생략해도public이며 기본적으로 생략한다.
Modifier 'protected' not allowed here
: 인터페이스는 protected 접근 제한자를 허용하지 않는다.
- 접근 제한자를 명시하지 않는다고 해도 위 메서드의 접근 제한자는 default가 아니다. 인터페이스가 가지는 모든 접근 제한자는 public이기 때문에 생략하는 것이다.
기본적으로 추상적이다.(구현부를 가지지 않는다.)
Interface abstract methods cannot have body: 인터페이스 추상 메서드는 구현부를 가질 수 없다.- 기본적으로 추상적(구현부를 가지지 않는다.) 생략해도 abstract이며 기본적으로 생략한다.
implements 인터페이스 이름,...
- 인터페이스는 콤마로 구분하여 여러개 구현할 수 있음. (인터페이스만!)
Class 'Wraith' must either be declared abstract or implement abstract method 'fly()' in 'IFly'이 클래스를 IFly 인터페이스를 구현하게 하고 싶으면 IFly가 가진 fly()라는 추상메서드를 구현하거나 Wraith가 추상클래스여야한다. 라는 오류가 뜬다.
Wraith가 추상적이게 되면 객체화를 할 수 없다.
Wraith wraith = new Wraith();
그렇기 때문에 fly()메서드를 재정의하자!
메인으로 넘어와서 Wraith 객체화하고 호출해보자.
- toString을 재정의 했기 때문에
[TERRAN] 레이스이런 형태로 출력이 된다.
부모로 부터 자식객체를 받을 수 있기 때문에 Wraith 객체를 오브젝트 타입, 유닛 타입으로 받을 수 있다.
- Unit은 attack 메서드를 가지는데 objWraith로는 범위가 제한되있기 떄문에 호출하지 못한다.
- 인터페이스도 객체를 가질 수 있다.
- fly만 있고 attack이 없다.
상속을 받을 때 부모 객체를 자식들이 받을 수 있는 것처럼
구현하는 인터페이스로도 객체를 받을 수 있다. 그렇지만 부모 자식 관계는 아니다!!
![]()
IFly flyMarine = marine;
ClassCastException: 클래스 형변환 예외 발생- marine 객체의 타입인 Marine은 IFly 인터페이스를 구현하지 않음으로 IFly 타입으로 자동 형변환 될 수 없다.
Unit클래스로 가서 attack메서드에 공격 대상 기능을 추가하자.
유닛만 공격 대상이 될 수 있도록 하자.
- Unit을 상속받아 attack메서드를 구현하고 있는 클래스 모두 같이 수정해줘야함.
- %s는 문자열을 나타내기 위해 존재한다고 헀는데 this와 target은 둘 다 stringd이 아니다.
모든 레퍼런스 타입을 String 타입으로 변환하는 방법에 toString이 있다.
%s자리에 문자열이 아닌 것이 들어가게 되면 객체의 toString을 호출한다.
this.toString() / target.toString() 이렇게 쓰며 생략가능하다.
유닛의 이름만 알고 싶다면 this.getName() 으로 작성하면 된다.
getName은 유닛이 가지고 있기 때문에 this(나), target도 호출이 가능한 것이다.
- 질럿은 레이스(날아다니는 유닛)를 공격하지 못해야하는데 공격을 할 수 있게 되있다. 막아줘야한다.
Wraith, Marine, Zealot에서 다 똑같은 attack의 구현부를 가지기 때문에 추상적으로 만들어가면서까지 구현을 다 할 필요없다.
- Unit 클래스에서 attack메서드의 접근 제한자를 abstract에서 defalut로 바꿈으로써 딱 한번만 구현하게 된다.
- 즉, Wraith, Marine, Zealot 에서 재정의하지 않아도 된다.
Zeolot이 공중공격할 수 없도록 해보자.
- attack 메서드 재정의
super.attack(target);: 메서드를 재정의했을 때 타입을 어떤 것으로 바꾸든 재정의 된 메서드가 호출이 되었다.
재정의되기 전 부모의 내용을 호출할 수 있는 유일한 방법은 super을 통하여 메서드를 직접호출하면 된다.
Zeolot이 target(공격대상)으로 하여금 공격할 수 있는 대상인가?
target이 날아다니는가에 대한 여부를 먼저 따지자.
전달받은 Unit이 IFly를 구현받고 있는가에 대한 여부를 확인 해보자.
if(객체 instanceof 타입) { }: 객체가 명시한 타입으로 형변환 될 수 있는가? 에 대한 여부 반환
- target 객체가 IFly 타입으로 형변환 될 수 있는가? 에 대해 안전하게 물어보는 것이다.
( 억지로 형변환해서 오류터트려서 예외를 막는 방법도 있지만 instanceof을 훨씬 훨씬 많이 쓴다.)- 앞에 객체가 와야하고 뒤에 타입이 와야한다.
- boolean타입으로 반환이 되고 따로 변수로 빼서 사용할 수도 있지만 이렇게 안한다.
- target이 IFly타입으로 형변환될 수 있다면 해당 공격대상은 날아다니다는 것임으로 공격할 수 없게 하면 된다.
어떠한 유닛이 공격을 할 때 공격 대상이 날아다니고 공격을 하는 대상이 공중공격을 못하면 막아야한다.
- Zergling 생성 (날아다닌다.)
- Zeolot에 attack 메서드를 재정의한 것처럼 Zergling에 attack 메서드 재정의 하지 않아서 이런일이 발생했다.
- 이런 재정의를 일일히 다 해줄수가 없기 때문에 인터페이스를 사용한다.
지상공격을 할 수 있다. 공중공격을 할 수 있다. 라는 건 Unit의 속성이다.
공중공격을 할 수 있다라는 인터페이스를 만들자.
- 이 인터페이스를 가진 유닛을 공중공격을 할 수 있다 라는 걸 알려준다.
![]()
- IAttactAir가 추상메서드를 하나도 안가지고 있기때문에 재정의 할 게 없다.
공격 대상인 target이 공중유닛(IFly)이고 내가 공중공격을 할 수 없음(!~IAttackAir) ::: 공격하면 안됨
target instanceof IFly && !(this instanceof IAttackAir)) 공격대상이 공중유닛이고 내가 공중공격 속성을 가지고 있지 않을 때
-> 질럿도 저글링도 attack 메서드를 재정의를 할 필요 없다. (삭제) 위의 attack메서드에서 다 해결이 된다.
marine.attack(wraith);
wraith : IFly && marine : IAttackAir
wraith.attack(wraith);
wraith : IFly && wraith : IAttackAir
zealot.attack(wraith);
wraith : IFly && zealot : IAttackAir (x)
zergling.attack(wraith);
wraith : IFly && zergling : IAttackAir (x)
zealot.attack(zergling); wraith : IFly (x)
공격 대상과 자기 자신이 "같은 객체" 일때 자살 방지를 하자
- 받아온 target과 this가 같다면 죽이지 못하게끔 해주면 된다.
marine.attack(marine); ↑ this ↑ target
- 레퍼런스타입은 주소값을 비교해야함.