자바 인터페이스 상속 예제 - jaba inteopeiseu sangsog yeje

우리는 VCR클래스와 TV클래스, 두 클래스를 동시에 상속해 TVCR이라는 클래스를 만들려고 한다. 하지만 자바에서는 말했다시피 다중상속이 안된다. 그렇기 때문에 인터페이스를 이용하여 다중상속처럼 만들었다.

방법의 순서는 아래와 같다.


  1. VCR에서 사용되는 메서드를 그대로 이름을 따와 IVCR이라는 인터페이스를 만들었다.
  2. 최종적으로 구현하려는 TVCR클래스에 TV클래스를 상속하고 IVCR이라는 인터페이스의 메서드를 TVCR클래스에서 구현하겠다고 implements로 선언했다.
  3. VCR클래스의 인스턴스를 생성하여 오바라이딩된 IVCR의 메서드에서 VCR의 메서드를 호출한다.

위와 같이 만들면 TV클래스와 VCR클래스의 모든 메서드와 멤버를 사용할 수 있다. 즉 다중상속과 같아진다.



※ 인터페이스와 상속의 다형성 비교

그럼 일단 인터페이스의 다형성에 대해 알아보기전에 상속과 인터페이스의 다형성에대해 잠깐 비교해보자.

상속의 다형성의 기본형태는 부모클래스 p = new 자식클래스() 이다. 부모클래스p가 참조할 클래스는 자신의 클래스보다 범위가 넓거나 같아야 한다.

즉 아래 소스처럼 부모클래스 자신을 참조하거나 자신보다 범위가 넓은 자식클래스를 참조해야한다.


class Car {/*구현*/}


class FireEngine extends Car {/*구현*/}


public static void main(String[] args) {


    /*자기 자신을 참조하여 객체 생성*/

    Car c = new Car();


    /*자기 자신보다 범위가 넓은 자식클래스를 참조하여 객체 생성*/

    Car c1 = new FireEngine();

    

    /*형변환 하여 객체 생성*/

    FireEngin f = (FireEngine)new Car();


}


단 c1객체의 경우 FireEngine()을 참조하고 있지만 Car의 인스턴스이므로 Car클래스에 정의된 멤버만 사용이 가능하다.

f객체의 경우 Car()를 참조했지만 FireEngin()으로 형변환을 했으므로 FireEngin클래스의 메서드를 사용할 수 있다.

f는 형변환을 하지 않으면 에러가 난다.

참고로 c는 Car의 인스턴스이고 c1은 Car의 인스턴스이자 FireEngine의 인스턴스이다.


이제 인터페이스의 경우에서의 다형성을 보자

public class InterfaceTestClass implements InterfaceTest1 , InterfaceTest2, InterfaceTest3{/*구현*/}


public static void main(String[] args) {

    InterfaceTest1 i1 = new InterfaceTestClass();

    InterfaceTest2 i2 = new InterfaceTestClass();

    InterfaceTest3 i3 = new InterfaceTestClass();

}



위에서 보다시피 InterfaceTest1,2,3는 인터페이스이다. 그리고 InterfaceTestClass는 클래스이다.

즉 인터페이스 i = new 클래스()와 같은 형태로 인터페이스 객체를 만들어 다형성을 사용할 수 있다.

아마 InterfaceTestClass에서는 InterfaceTest1,2,3의 모든 메서드들이 구현되어 있을것 이다. 

하지만 i1에서는 InterfaceTest1의 메서드만 사용가능하고 i2는 InterfaceTest2의 메서드만 사용이 가능하고 i3은 InterfaceTest3의 메서드만 사용이 가능하다.



※ 인터페이스의 다형성 사용 예시

상속의 다형성의 사용법은 아래 다형성과 상속의 글에서 썻기 때문에 자세한 설명은 하지 않겠다.

그렇다면 이러한 인터페이스의 다형성을 이용하여 무엇을 할 수 있을까?

스타크래프트를 예로 들어보자. 

SCV, 탱크, 레이스, 마린 네가지의 유닛이 있다고 하자. 이 네 유닛은 기본적인 유닛의 특성을 정의해 놓은 멤버가 있는 Unit이라는 클래스를 상속받아  구현된다 하자.

여기서 SCV의 수리기능은 탱크와 레이스에는 사용할 수 있지만 마린에는 사용할 수 없다. 

그렇다면 SCV의 수리 메서드는 아래와 같이 만들어야 할 것이다.


void Repair(Tank t){

    //수리 기능

}


void Repair(Wraith w){

    //수리기능

}


하지만 이런식으로 만들면 Repair메소드가 엄청나게 많아질 것이다. 그렇다고 상속의 다형성을 이용하기에는 개념적으로 애매한 면이 있다.

탱크와 마린, 레이스는 모두 유닛이라는 클래스를 상속받아야 하기 때문에 수리가 되고 안되는 것을 구분할 기준이 없다.

그래서 인터페이스를 사용해서 아래와 같이 탱크와 레이스, 마린의 클래스를 정의해보자.


public class Unit {

      

      public String name;

      

      public void move(){

            System.out.println("이동");

      }

}


public class Wraith extends Unit implements Reparable{

      

      public Wraith() {

            name = "Wraith";

      }

      

      public void attack(){

            System.out.println("뿅뿅");

      }

}


public class Tank extends Unit implements Reparable{

      

      public Tank() {

            name = "Tank";

      }

      

      public void attack(){

            System.out.println("퉁퉁");

      }

}


public class Marine extends Unit{

      public Marine() {

            name = "Marine";

      }

      

      public void attack(){

            System.out.println("두두");

      }

}


public class Scv extends Unit implements Reparable{

      

      public void Repair(Unit u){

            

            if( u instanceof Reparable){

                  System.out.println(u.name + " 지이잉 수리");

            }else{

                  System.out.println(u.name + " 수리할수 없는뎁쇼?");

            }

      }

}


Reparable인스턴스를 만들어 수리 가능한 유닛에 implements로 정의해 두었다. 그리고 Repair 메서드에서 Unit객체를 받아 Reparable이 포함되어 있는지 없는지를 구분하여 수리할지 말지를 정의한다.