이번엔 다형성에 대해 포스팅 하겠습니다.

사실 이 다형성이라는 개념은 이해하기 어렵게 느낄 수 있습니다

( 제가 그랬습니다..ㅠ)


간단하게나마 적으면서 저도 다시 정리해 보겠습니다.


다형성은 객체지향개념의 특징 중 하나입니다.

우리는 이 다형성을 확인하기 위한 기술을 몇가지 알고 있는데요.

오버라이딩, 상속이 다형성이라는 특징을 표현해 줍니다.

제가 앞으로 포스팅 할 예정인 추상메소드, 추상클래스, 인터페이스 역시 다형성을 표현하는 기능입니다.

상속과 관련된 것들이 모두 다형성을 표현하는데에 중요한 기능이 되는 것 입니다.


다형성이란것은 하나의 메소드나 클래스를 여러 방법으로 사용함을 의미합니다.

참고로 다형성을 알기 위해서는 상속에 대해서 잘 알고 계셔야합니다.



위와 같은 소스가 있습니다.

B클래스는 A클래스를 상속받고 있네요.

그리고 5번라인에서 객체를 만드는데요

우리가 평소 쓰던 방식이랑 조금 다릅니다.

평소 같으면 B Obj = new B(); 이런 식으로 사용 했겠죠?


하지만 5번라인이 이번 포스팅에서의 핵심입니다.

5번라인을 해석 해보면

B클래스를 Obj라는 변수에 인스턴스화 시켜서 넣었습니다.

그리고 그 데이터 타입은 클래스 A 입니다.

즉, 클래스B로 인스턴스를 만들었지만 클래스A의 형태를 가지고 있다는 겁니다.

한마디로 조상클래스타입의 참조변수가 자손클래스의 인스턴스를 참조하고 있다는 겁니다.


PolyDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.dreamstorage.Polymorphism;
 
public class PolyDemo {
    public static void main(String[] args) {
        Car car = new PoliceCar();
        car.drive();
        car.stop();
    //  car.criminal();    에러
    }
}
 
class Car{
    
    public void drive(){
        System.out.println("주행");
    }
    
    public void stop(){
        System.out.println("브레이크");
    }
}
 
class PoliceCar extends Car{
     public void criminal(){
         System.out.println("범죄자를 대려감");
     }
}
 
class Ambulance extends Car{
        public void patient(){
            System.out.println("환자를 후송하는 기능");
        }
}
 
 
cs

경찰차와 응급차를 만들었습니다.

PoliceCar와 Ambulance는 각각 Car클래스를 상속하고 있네요.

5번라인에서 PoliceCar클래스를 인스턴스화 시켰습니다. 그리고 Car의 타입인 car라는 객체를 만들었습니다.

그리고 그 객체의 drive(), stop(), criminal()를 호출하고 있습니다.

그리고 실행을 시켜보면 8번라인에 의해 실행이 되지 않습니다.


우리는 PoliceCar클래스를 car에 인스턴스화 시켰지만 car라는 변수는 클래스Car 타입이기 때문입니다.

Car클래스에 criminal()가 없기 때문에 자바는 criminal()이 없다고 보고 에러메시지를 보내게 됩니다.


조금 더 알아 봅시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.dreamstorage.Polymorphism;
 
public class PolyDemo {
    public static void main(String[] args) {
        Car car = new PoliceCar();
        car.drive();
        car.stop();
        car.siren();
    }
}
 
class Car{
    
    public void drive(){
        System.out.println("주행");
    }
    
    public void stop(){
        System.out.println("브레이크");
    }
    public void siren(){
        System.out.println("사이렌");
    }
}
 
class PoliceCar extends Car{
     public void criminal(){
         System.out.println("범죄자를 대려감");
     }
     
     @Override
     public void siren(){
         System.out.println("경찰차 사이렌");
     }
}
cs

응급차는 빼도록 하죠 ^^;


자 제가 소스를 조금 수정했습니다.

Car클래스에 siren()를 만들었구요.

PoliceCar클래스에 siren()을 오버라이드 하였습니다.


과연 8번라인에 의한 결과는 어떤 것이 출력 될까요?



이제 우리는 두 가지를 알 수 있습니다.


첫번째!!

PoliceCar클래스를 Car클래스타입으로 인스턴스화 하였을 때에 PoliceCar클래스의 criminal()는 아예 없듯이 실행이 되지 않는다.


두번째!!

PoliceCar클래스를 Car클래스 타입으로 인스턴스화 하였을 때에 siren()를 실행하니까 PoliceCar클래스에서 오버라이딩된 siren()이 실행되었다.


즉, Car타입으로 인스턴스화 하면 Car클래스에 있는 멤버들만이 PoliceCar클래스의 멤버가 됩니다.

또한 PoliceCar클래스에서 오버라이딩한 멤버라면 오버라이딩된 멤버를 우선적으로 호출합니다.


결론적으로 우리가 알아야 하는 것은


부모타입의 변수로 자식타입의 인스턴스를 참조할 수가 있다는 것입니다.

하지만 반대로는 안됩니다!!