본문 바로가기

Programming/JAVA

상속(6) - 타입 변환과 다형성 2

java logo image

 

 

 

앞서 상속과 관련하여, 다형성이란 성질에 대한 기본 개념을 다루어 보았습니다. 중요한 내용이니 잘 기억이 나지 않으신다면, 다시 한번 상기하고 오시는 것을 추천드립니다. 

 

 

 

상속(6) - 타입 변환과 다형성 1(★)

지금부터는 JAVA와 OOP 언어에서 핵심적이면서도 복잡한 내용을 가진 다형성에 대한 내용을 다루겠습니다. 우선, 다형성의 개념을 한 번 간단히 정의해 보자면 "같은 타입을 사용하지만, 다양한

nozeroslope.tistory.com

 

 

 

그럼, 이제는 다형성과 관련하여 [자동 타입 변환(Promotion)]에 대해서 살펴보도록 하겠습니다. 말 그대로, 프로그램 실행 도중에 자동으로 객체의 타입 변환이 일어나는 현상을 의미하는데요, 정확히 어떤 개념인지를 살펴보도록 하겠습니다. 특히 앞서 살펴본 내용 중, 자식 클래스는 부모 클래스의 성질을 모두 기본적으로 갖고 있기 때문에 부모 클래스 취급이 가능하다는 특성을 인지하고 있어야 합니다.

 

예를 들어보겠습니다. Smartphone이라는 부모 클래스가 있고, 이를 상속하는 자식 클래스인 Galaxy라는 클래스가 있다고 가정해 봅시다. 그럼 Galaxy는 Smartphone의 특성을 모두 갖고 있겠지요?(당연하지만) 그럼 'Galaxy는 곧 Smartphone이다'라는 명제가 성립한다는 의미입니다. 물론, 관념론적인 접근이 아니라 자바에서 클래스의 개념이니 오해는 없으시길 바랍니다. Galaxy는 Smartphone의 특성을 모두 기본적으로 갖고 있으니까요.

 

Smartphone을 상속받는 Galaxy 객체

 

 

위와 같이 각각의 클래스가 선언되고, 생성된 객체가 있다고 가정한다면, 위 두 개의 클래스가 선언될 때는 아래와 같은 방식으로 선언되었을 것입니다. 

 

class Smartphone {
	// ...
}

class Galaxy extends Smartphoen {
	// ...
}

 

이제 위의 클래스를 이용해 객체를 생성해 보도록 하겠습니다. 이 때 주의할 것은, Smartphone 타입의 변수에 Galaxy 타입의 객체를 대입한다는 점 입니다. 위에서 말했다시피, Galaxy는 Smartphone이라는 부모 클래스의 특성을 모두 갖고 있기 때문에 이러한 대입이 가능합니다. 이 때는, 우리가 처음 언급한 '타입의 자동 변환'이 이루어집니다. 현실세계 기준으로는 말이 조금 어색할 수 있지만, [자식은 부모 행세를 할 수 있다]는 것이죠.

 

이 과정을 코드로 나타내 보겠습니다. 

 

Galaxy galaxy = new Galaxy();
Smartphone smartphone = galaxy;

// 위 코드를 한 줄로 축약하면 다음과 같습니다.
Smartphone smartphone = new Galaxy();

 

위의 과정이 이해가 되셨나요? 위에서 예시로 든 스택 영역에 존재하는 smartphone이라는 변수는, 힙 영역의 어떤 객체를 참조하나요? 다름 아닌 galaxy 객체를 참조하고 있습니다. 참조하는 것은 Galaxy 클래스의 변수이지만, 대외적으로는 Smartphone 클래스 타입으로 사용되는 것입니다. 위 코드의 첫 두 줄을 도식화한다면 아래와 같습니다. 

 

 

 

설명했다시피, 두 개의 변수 smartphone과 galaxy는 Galaxy 타입의 객체를 동일하게 참조하는 구조가 됩니다. 예시 코드의 넷 째줄에 있는 smartphone 객체 역시 Galaxy 객체를 참조하는 구조가 되겠죠? Smartphone 타입의 변수 역시 Galaxy타입의 객체를 참조한다는 것이 포인트입니다. 그리고, 그 Galaxy 타입의 객체가 Smartphone 타입의 객체를 상속하고 있다는 점을 잊지 말아야 합니다. 참고로 위 도식에서 등장하는 변수 smartphone과 galaxy 변수를 == 연산자를 통해 결과를 산출하면 true가 출력됩니다. 이를 통해서도 두 변수 모두 동일한 객체를 참조하고 있다는 사실을 증명할 수 있죠.

 

 


 

 

여기서 그럼, 이런 형태로 자동변환이 일어난 이후, 이러한 변수들이 어떤 특성을 갖는지가 중요하겠죠? 위의 예제를 기준으로 아래와 같이 smartphone 변수를 선언했다고 다시 가정합시다. 

 

Smartphone smartphone = new Galaxy();

 

이러한 경우 우리는 smartphone 변수는 Smartphone 타입의 변수이지만, 실제로는 Galaxy타입의 객체를 참조하고 있다는 중요한 기본 구조를 이해했습니다. 하지만, 주의할 점! 실제로 코드상에서 smartphone이라는 변수를 사용할 때 실제로는 Smartphone 클래스에 선언된 필드와 메서드만 접근이 가능하다는 점 입니다. 이것은, 일상적인 관념으로 설명하자면 "자식이 부모 행세를 하고 있기 때문에, 부모로서의 행동만 가능하다"라고 이해하시면 됩니다. Galaxy 클래스를 참조하지만, Smartphone에 선언된 필드와 메서드만 쓸 수 있다는 것이죠. 예외적으로 자식 클래스에 선언된 메서드를 사용할 수 있는 경우도 있습니다. 바로, 부모 클래스에 선언된 메서드가 자식 클래스에서 오버라이딩을 통해 재선언 되었을 경우죠.