본문 바로가기
언어/Java

OOP의 특성 - 2. 다형성

by 넬준 2022. 5. 13.

 

다형성이란 단어를 살펴보면, 다양한 형태를 가지는 성질이라고 풀이할 수 있다.

 

이를 프로그래밍에 적용해보면, 다음과 같다.

 

하나의 객체는 여러 타입을 가질 수 있다.

 

프로그래밍에서는 타입을 구현하는 방식 중 하나로 '클래스'라는 개념을 주로 사용하기 때문에, 위 내용을 조금 바꿔보면 다음과 같다.

 

하나의 객체는 여러 클래스를 가질 수 있다.

 

여기서 객체가 아무 클래스나 다 가질 수 있는 것은 아니다.

 

객체는 기본적으로 자신의 클래스를 가지고 있다. 거기에 자신의 클래스와 상속관계에 있는 상위 클래스, 하위 클래스를 가질 수 있다.

 

 

타입 변환

타입 변환이라는 개념은 기본자료형 내용에서도 등장한다.

기본 자료형만 타입 변환이 가능한 것이 아니라 참조 자료형도 타입 변환이 가능하다.

 

자동 타입 변환

단어에서도 알 수 있듯이 자동으로 타입이 변환된다는 의미이다.

 

그럼 과연 언제, 어떤 상황에서 자바가 자동으로 타입을 변환하는 것일까?

 

바로 상위 클래스로 타입을 변환하는 경우이다.

 

Upper 클래스가 Lower 클래스의 상위 클래스일 때, 아래 코드를 살펴보자.

 

Lower a = new Lower();
Upper b = a;

 

변수 b는 Upper 클래스 참조자료형 변수다.

하지만 두 번째 줄을 보면 변수 b에 Lower 클래스 참조자료형 변수 a가 대입된 것을 볼 수 있다.

 

여기서 하위 클래스인 Lower 클래스 자료형에서 상위 클래스인 Upper 클래스 자료형으로 자동 타입 변환이 된 것이다.

 

해당 코드를 실행하고서 메모리의 상태를 보면, 다음과 같다.

 

앞서, 생성자의 맨 첫줄에 super()가 호출되어 상위 클래스의 인스턴스가 먼저 생성되고 나서, 본인 클래스의 인스턴스가 생성된다고 했었다. 해당 내용을 기억하고 아래 그림을 보면 이해가 쉽다.

 

 

변수 a와 b는 같은 참조값을 가지고 있다. 실제 두 변수를 ==비교하면 true가 나오는 것을 알 수 있다.

 

System.out.println(a==b); //true 출력

 

여기서 주의할 점이 있다.

 

위에서 봤듯이, 두 변수는 같은 참조값, 즉, 메모리에서 같은 주소값을 가리키고 있지만 접근 가능 범위가 다르다.

 

만일 상위 클래스로 자동 타입 변환이 일어났다면, 상위 클래스에 선언된 필드와 메소드에만 접근할 수 있다.

 

 

그림에서와 같이 변수 b는 Upper 클래스의 인스턴스에만 접근이 가능하다. 즉, Upper클래스의 인스턴스 멤버(필드, 메서드)에만 접근할 수 있다.

 

하지만, 만일 상위 클래스의 메서드가 하위 클래스에서 오버라이딩이 되었다면, 해당 메서드를 호출하면 상위 클래스의 메서드 대신 오버라이딩된 하위 클래스에서의 메서드가 호출된다.

 

b에서 Lower 클래스의 멤버인 age 필드와 showAge 메서드로 접근할 수 없고,

 

print 메서드를 호출하면 Upper 클래스의 print 메서드가 아닌 Lower 클래스에서 오버라이딩한 print 메서드가 호출되어 "Lower 클래스에서 오버라이딩한 print() 호출"이 출력되는 것을 확인할 수 있다.

 

 

강제 타입 변환

그러면 반대로 하위 클래스로의 타입을 변환해야할 때는 강제로 타입을 변환해야한다.

 

 

Lower 클래스 타입으로 타입 변환을 해주지 않아서 에러가 난 것을 볼 수 있다.

 

Upper c = new Lower();
Lower d = (Lower)c;

 

이 같이 하위 클래스로의 형변환이 필요할 때는 (하위 클래스 타입)을 적어 명시적으로 형변환을 해야한다.

 

instanceof

Upper e = new Upper();
Lower f = (Lower)e;

위 코드를 실행하면 다음 ClassCaseException이 뜬다.

상위 클래스인 Upper 클래스 자료형인 변수 e를 하위 클래스인 Lower 클래스 자료형으로 형변환할 수 없다는 의미이다.

 

전의 경우는 상위 클래스 변수가, 상위 클래스로 자동 타입 변환한 하위 클래스 객체를 참조한 것이고, 이번에는 상위 클래스 변수가 자기 자신의 클래스 객체를 참조한 것이다.  

이럴 때에는 하위클래스로 타입을 변환할 수 없다.

 

같은 상위 클래스 변수(c, e)인데 자기 자신의 클래스 객체를 참조한 것인지 하위 클래스 객체를 자동 타입 변환해서 참조한 것인지 어떻게 알 수 있을까?

 

바로 instanceof 연산자를 통해 알 수 있다.

 

객체 instanceof 클래스명

 

객체가 해당 클래스의 객체라면 true, 아니면 false를 리턴한다.

 

강제 타입 변환이 필요한 경우, instanceof 연산자로 확인한 뒤 안전하게 타입을 변환해야 한다.

'언어 > Java' 카테고리의 다른 글

Arrays.asList()  (0) 2022.05.30
배열과 맵 toString()  (0) 2022.05.25
OOP의 특성 - 1. 상속  (0) 2022.05.12
생성자  (1) 2022.05.11
static  (0) 2022.05.10

댓글