본문 바로가기
Java

Class(6)-Polymorphism(다형성)

by GGShin 2022. 4. 29.

이번에는 class의 핵심 요소 중 하나인 Polymorphism(다형성, 多形性)에 대해서 알아보겠습니다.

다형성이라는 특성 때문에 부모 클래스 타입의 참조변수로 자식 클래스의 인스턴스를 참조할 수가 있습니다.

지금까지 클래스 타입의 참조변수를 만들 때는 참조변수의 타입과 인스턴스 타입이 일치했습니다.

예를 들어서, 

 

1
2
Movie movie = new Movie();
ForrestGump forrestGump = new ForrestGump();
cs

 

위와 같은 형태였습니다. 하지만 다형성을 이용하면, 두 클래스가 상속관계라는 전제 하에 부모 클래스의 참조변수로 자식 클래스 인스턴스를 참조할 수가 있습니다. (여기에서는 Movie class 가 부모 클래스, ForrestGump가 자식 클래스 입니다.)

 

1
2
Movie movie = new ForrestGump(); //upcasting
ForrestGump forrestGump = new ForrestGump();
cs

 

이런식으로 말입니다. Line#1을 보면 부모 클래스인 Movie의 참조변수 movie가 자식 인스턴스 ForrestGump() 를 참조하고 있습니다.

다형성이라는 단어의 한자를 살펴보면 다형(多形) 즉, 여러개의 형태를 가질 수 있다는 의미입니다. 바로 부모 클래스 타입의 참조변수로 여러 타입(자식 클래스 타입)의 객체를 참조할 수 있다는 말입니다. (부모라는 이름으로 자기의 자식들 집을 여기저기 탐방다니는 듯한 느낌이었습니다.)

예시를 통해 조금 더 자세히 살펴보겠습니다.

먼저 Movie라는 class를 만들어 보았습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
class Movie {
    private String title;
 
    public Movie(String title) {
        this.title = title;
    }
 
    public String plot() {
        return "등록된 줄거리가 없습니다.";
    }
}
cs

 

title이라는 private field와 plot이라는 public method가 있네요. 그리고 title을 initialize하는 constructor까지 만들었습니다.

이제는 한 번 Movie class를 상속하는 클래스를 3개 만들어보겠습니다.

 

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
class LoveActually extends Movie{
    public LoveActually() {
        super("Love actually");
    }
    @Override
    public String plot(){
        return "To me, you are perfect.";
    }
}
class Interstellar extends Movie {
    public Interstellar() {
        super("Interstellar");
    }
    @Override
    public String plot(){
        return "Love is the one thing that transcends time and space.";
    }
}
 
class Undefined extends Movie {
    public Undefined() {
        super("Undefined");
    }
    //plot() method 오버라이드 하지 않음.
}
cs

 

왠지 모르지만 영화하면 항상 생각나는 러브액츄얼리와 제가 좋아하는 인터스텔라 클래스를 만들어보았습니다. 마지막에 있는 클래스는  Undefined라는 이름으로 만들었고 이 클래스만 plot() method를 override 하지 않았습니다.

보시면 세개의 클래스 모두 Movie를 extends (=상속 표시) 했고, constructor도 같이 상속한 것을 보실 수 있을 겁니다. (Object를 만들 때 title을 따로 parameter로 받지 않도록 각각 영화의 타이틀을 미리 넣어두었습니다 (super 부분). )

이제 주목해야 할 부분은 바로 @Override 된 plot() method입니다. 

두 하위 클래스 모두 plot() 함수를 override 하였지만 return 하는 내용은 모두 다릅니다.

 

한번 자식 클래스 인스턴스를 부모 클래스 참조변수가 참조하도록 한 뒤(upcasting), plot()을 실행해보겠습니다.

(보통은 참조변수의 클래스 타입과 인스턴스의 클래스 타입이 일치하는데요, 지금과 같이 부모 클래스 참조변수가 자식 클래스 인스턴스를 참조하는 경우Upcasting 이라고 합니다! 다음번에 한 번 좀 더 자세히 알아보겠습니다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
 
    public static void main(String[] args) {
       Movie loveActually = new LoveActually();
       Movie interstellar =new Interstellar();
       Movie undefined = new Undefined();
 
        System.out.println(loveActually.plot());
        System.out.println(interstellar.plot());
        System.out.println(undefined.plot());
    }
 
}
cs

 

과연 어떤 결과가 나올까요?

 

 

보시면 Movie 클래스에 정의된 plot()이 아닌 각 자식 클래스에 정의된 plot()의 내용에 해당하는 값을 리턴하고 있음을 확인할 수 있습니다!

어떻게 이런 일이 생기는 걸까요? 자식 클래스에 부모 클래스에서 override한 method가 있는 경우에는 자식 클래스에 있는 method를 호출하기 때문입니다. 하지만 Undefined class의 경우는 plot()을 override 하지 않았기 때문에 부모 클래스에 있는 plot() method가 호출된 것입니다.

만약에 부모 클래스에는 없고 자식 클래스에만 있는 method를 실행하면 어떻게 될까요?

LoveActually class에 Moive class에는 없는 runnigTime() method를 만들었습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
class LoveActually extends Movie{
    public LoveActually() {
        super("Love actually");
    }
    @Override
    public String plot(){
        return "To me, you are perfect.";
    }
 
    public int runningTime(){
        return 120
    }
}
cs

 

과연 아래 loveActually.runningTime()은 작동할까요?

 

1
2
3
4
5
6
7
8
9
10
11
public class Main {
 
    public static void main(String[] args) {
 
       Movie loveActually = new LoveActually();
 
        System.out.println(loveActually.runningTime());
        
    }
 
}
cs

 

정답은 compile error를 발생시킨다는 것입니다. 부모 클래스 참조변수로 자식 클래스 타입의 인스턴스를 참조하는 경우에는 자식 인스턴스만이 가진 method를 사용할 수 없습니다. 즉, 부모 클래스가 가지고 있는 method만 사용할 수 있는 것입니다. (부모가 평생 해보지 않은 행동을 자식이 하면 부모는 이해를 못하죠..그렇게 기억하면 좋을 것 같습니다 ㅎㅎ)

 

이렇게 method override를 통해 다형성을 이뤄내는 것을 다른 말로 runtime polymorphism (런타임 다형성) 이라고 부르기도 합니다. Dynamic Method Dispatch 라고도 하는데요, 두가지는 조금 더 공부를 해본 후에 다음번에 얘기해보도록 하겠습니다!

 

제안사항이나 의문점은 알려주시면 같이 생각해보겠습니다! 감사합니다 ☺️ 

반응형