본문 바로가기

플밍 is 뭔들/JAVA

[자바] 다형성 (Polymorphism)

※ 다형성
다형성이란 '여러 가지 형태를 가질 수 있는 능력'으로써 자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로 구현

  1. 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 함.
ex)
class Parent{
    
    int num1;
    int num2;

    void parnetMethod(){
        ...
    }
}

class Child{

    String str;
    
    void childMethod(){
        ...
    }
}


public static void main(String[] args){

    Parent p = new Child(); //이런 형태가 가능하다.
    Child c = new Child();
}


위에서 보다시피 Parent p = new Child()와 같이 조상클래스 타입의 참조변수로 자손클래스 인스턴스를 참조하여도 에러가 나지 않는다. Parent p = new Child(); 이것과 Child c = new Child();는 같은 인스턴스를 참조하고 있지만 이 둘의 차이는 무엇일까? 
바로 사용할 수 있는 멤버의 개수이다. 자손클래스의 인스턴스를 참조한 조상클래스는 조상클래스의 멤버만 사용 할 수 있고 자손의 멤버인 str과 childMethod()는 사용할 수 없다. 그래서 p.str;p.childMethod()와 같은 접근이 불가능하다.

그렇다면 그 반대는 가능할까?
ex)
Child c = new Parent();


이러한 접근은 불가능하다. 왜냐하면 참조할 수 있는 멤버가 자손클래스가 더 많기 때문이다. 
(상속의 개념상 자손클래스는 부모의 멤버 + 자기 자신의 멤버의 범위를 가지고 있기 때문)

그렇다면 왜왜왜 인스턴스타입과 일치하는 인스턴스를 참조하면 되는데 왜 불편하게 자손클래스의 인스턴스를 참조하는 이유는 무엇일까?

** 참조변수의 형변환 **
위에서 처럼 Parent p = new Child(); 의 형태로 선언을 하면 p는 Parent의 인스턴스이기도 하며 Child의 인스턴스이기도 하다. 아래그림과 같이 상속했을 때를 생각해보자.

FireEngine 객체와 Ambulance 객체는 서로 아무 연관도 없지만 같은 조상을 가지고 있다. 그렇기 때문에 상황에 맞게 형변환을 하여 사용하면 편리하게 사용할 수 있다.
아래 소스를 보자.
public static void main(String[] args) {
    // TODO Auto-generated method stub
                  
    Car c1 = new FireEngine();
    Car c2 = new Ambulance();
    if(c2 instanceof FireEngine){
        System.out.println("소방차객체일까?");
    }
            
    if(c1 instanceof Ambulance){
        System.out.println("엠뷸런스객체일까?");
    }
            
    if(c1 instanceof FireEngine){
        System.out.println("소방차객체이다!");
    }
            
    if(c2 instanceof Ambulance){
        System.out.println("엠뷸런스객체이다!");
    }
            
    if(c1 instanceof Car){
        System.out.println("자동차객체!");
    }
            
    if(c2 instanceof Car){
        System.out.println("자동차객체!");
    }
            
    //각자의 자손에 맞는 형변환을 통해 그 인스턴스의 메서드를 사용할 수 있도록 형변환
    Ambulance a = (Ambulance)c2;
    FireEngine f = (FireEngine)c1;
            
    a.siren();
    f.water();
}

*********결과************

소방차객체이다!
엠뷸런스객체이다!
자동차객체!
자동차객체!
사이렌을 울립니다. 삐뽀삐뽀
물을뿌립니다. 쉬이이이익

instanceof는 참조변수가 참조하고 있는 인스턴스의 실제 타입을 비교하여 true, false로 알려주는 연산자이다.
(instanceof의 왼쪽에는 참조변수, 오른쪽엔 타입(클래스명)이 피연산자로 위치한다)
이 연산자를 이용하여 객체들을 비교한 결과들을 봤을 때 c1은 FireEngine의 인스턴스이기도 하며 Car의 인스턴스이다. 그리고 c2는 Ambulance의 인스턴스이기도 하며 Car의 인스턴스이기도 하다.
그리고 아래에는 c1,c2를 각각 자손타입에 맞게 형변환하여 메서드에 접근하면서 끝이 난다.

우리는 이러한 다형성을 이용한 형변환의 특징을 이용하여 소스에 활용 할 수 있다. 

  1. 매개변수의 다형성
          - 예를들어 병원과 소방서에서 자동차를 구매한다고 하자. 그리고 buy라는 메서드가 구입하려는 자동차를 
 매개변수로 받아 구매를 해준다라고 가정해보자. 

//병원에서 엠뷸런스를 구매할 때 
void buy(Ambulance c){
    ...
}

//소방서에서 소방차를 구매할 때
void buy(FireEngine c){
    ...
}

위에서와 같이 매개변수마다 메서드를 만들어 줘야 한다. 하지만 다형성을 이용한 형변환을 이용한다면 아래와 같이 만들 수 있다.

//자동차를 구매할 때
void buy(Car c){
    ...
}


  1. 여러 종류의 객체를 하나의 배열로 다루기
          - 예를들어 여러 자동차의 종류를 한 배열에 넣고 처리해야 할 일이 있다고 가정해보자.
            그렇다면 아래와같이 배열에 넣어 처리하면 쉽게 코드작성이 가능하다.

ex)

Car car[] = new Car[4];
car[0] = new FireEngine();
car[1] = new Ambulance(); 
car[2] = new Truck();
car[3] = new Sedan();

....

void buy(Car[] car){
    ...
}




'플밍 is 뭔들 > JAVA' 카테고리의 다른 글

[자바] 인터페이스 (Interface)  (0) 2017.09.19
[자바] 추상클래스 (Abstract Class)  (0) 2017.09.18
[자바] 제어자(Modifier)  (0) 2017.09.18
[자바] 상속  (0) 2017.09.11
[자바] 오버로딩 / 오버라이딩  (0) 2017.09.11