다형성이란?
-여러 가지 형태를 가질 수 있는 능력으로, 자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함
무슨 말이냐?? 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하였다는 것
(※참고: 조상클래스 = 부모클래스, 자손클래스 = 자식클래스)
아래 예시를 보며 자바에서의 '다형성' 의미를 알아봅시다.
예시)
왼쪽 사진) TV클래스 (부모클래스)
오른쪽 사진) TV클래스를 상속받고 있는 CaptionTV 클래스 (자식클래스)
생성된 TV클래스와 CaptionTV 클래스를 다루기 위해, 일반적으로 인스턴스의 타입과 일치하는 타입의 참조변수를 사용하면 아래와 같습니다.
TV t = new TV(); //TV클래스에서만 선언된 변수 및 메소드 호출가능
CaptionTV c = new CaptionTV(); //TV클래스를 상속받아서, TV클래스 & CaptionTV클래스에 선언된 변수 및 메소드 호출가능 |
하지만 두 클래스가 서로 상속관계에 있을 경우, 다음과 같이 부모 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조하도록 하는 것도 가능!
그렇다면 인스턴스를 같은 타입의 참조변수로 참조하는 것과 부모타입의 참조변수로 참조하는 것은 어떤 차이가 있나?
: 둘 다 같은 타입의 인스턴스(ex. CaptionTV())지만 참조변수의 타입(ex. c와 t)에 따라 사용할 수 있는 멤버의 개수가 달라짐
부모클래스 타입의 참조변수 t로는 CaptionTV 인스턴스의 모든 멤버 사용 X
CaptionTV c = new CaptionTV();
c.power;
c.channel;
c.power();
c.channelUp();
c.channelDown();
c.text;
c.caption();
|
TV t = new CaptionTV();
t.power;
t.channel;
t.power();
t.channelUp();
t.channelDown();
t.text; //사용불가
t.caption(); //사용불가
|
참고로
자식타입의 참조변수로 부모타입의 인서턴스 참조는 불가능함. 왜냐하면 실제 인스턴스인 TV의 멤버개수보다 자식클래스에서 사용할 수 있는 멤버 개수가 더 많기 때문에 이를 허용하지 않음
ex)
1
2
3
4
5
6
7
8
9
10
11
12
13 |
class Parent { ... }
class Child extends Parent { ... }
...
Parent p = new Parent(); // 허용
Child c = new Child(); // 허용
Parent pc = new Child(); // 허용
Child cp = new Parent(); // 오류 발생 |
|
정리하면, 부모타입의 참조변수로 자식타입의 인스턴스를 참조할 수 있다.
하지만 자식타입의 참조변수로 조상타입의 인스턴스는 참조할 수 X
다형성) 참조변수와 인스턴스의 연결
-부모 클래스에 선언된 멤버변수와 같은 이름의 인스턴스변수를 자식 클래스에 중복했을 때,
참조변수의 타입에 따라 서로 다른 결과를 얻음
즉 Child cp = new Child(); 와 Parent pc = new Child();는 서로 다른 결과를 얻음
★메서드의 경우, 부모 클래스의 메소드를 자식클래스에서 오버라이딩한 경우에도 참조변수 타입과 관계없이 오버라이딩된 메소드가 호출되지만, 멤버변수의 경우 참조변수의 타입에 따라 달라짐
-그렇다면 멤버변수가 어떻게 달라지나?
-부모클래스타입의 참조변수를 사용했을 때는 (ex. Parent p = new Child(); ) 부모클래스에 선언된 멤버변수가 사용됨
-자식클래스타입의 참조변수를 사용했을 때는 (ex. Child c = new Child(); ) 자식클래스에 선언된 멤버변수가 사용됨
ex)
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 |
public class MainClass {
public static void main(String[] args) {
Parent p = new Child(); //부모클래스타입의 참조변수를 사용
Child c = new Child(); //자식클래스타입의 참조변수를 사용
System.out.println("p.x = " + p.x); //멤버변수 호출
p.method(); //메소드 호출
System.out.println("c.x =" + c.x); //멤버변수 호출
c.method(); //메소드 호출
}
class Parent {
int x = 100;
void method() {
System.out.println("Parent method");
}
}
class Child extends Parent {
int x = 200;
void method() {
System.out.println("Child method");
}
}
}
|
cs |
결과
p.x = 100
Child Method
c.x = 200
Child Method |
다형성) 참조변수의 형변환
-서로 상속관계에 있는 타입간의 형변환은 양방향으로 자유롭게 수행 가능!!
-그러나 기본형 변수의 형변환에서 작은 자료형에서 큰 자료형의 형변환은 생략 가능하듯, 참조형 변수의 형변환에서는
자식타입의 참조변수를 부모타입으로 형변환하는 경우에 명식적인 형변환 생략 가능
● 자식타입 → 조상타입 (Up-casting) : 형변환 생략가능
● 조상타입 → 자식타입 (Down-casting) : 형변환 생략불가
-문법: (변환할타입의클래스이름) 변환할참조변수 |
ex)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
class Parent { ... }
class Child extends Parent { ... }
class Brother extends Parent { ... }
...
Parent pa01 = null;
Child ch = new Child();
Parent pa02 = new Parent();
Brother br = null;
pa01 = ch; // pa01 = (Parent)ch; 와 같으며, 타입 변환을 생략할 수 있음.
br = (Brother)pa02; // 타입 변환을 생략
br = (Brother)ch; // 직접적인 상속 관계가 아니므로, 오류 발생. |
cs |
다형성) instanceof 연산자
이러한 다형성으로 인해 런타임에 참조 변수가 실제로 참조하고 있는 인스턴스의 타입을 확인할 필요성 생김
자바에서는 instanceof 연산자를 제공하여, 참조 변수가 참조하고 있는 인스턴스의 실제 타입을 확인할 수 있도록 함
자바에서 instanceof 연산자는 다음과 같이 사용함
문법: 참조변수 instanceof 클래스이름 |
-주로 조건문에 사용되며 instanceof의 왼쪽에는 참조변수를, 오른쪽에는 타입(클래스명)이 피연산자로 위치
-그리고 연산의 결과로 boolean값이 true와 false 중의 하나를 반환
(true를 얻었다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 것을 뜻함)
ex)
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 |
class Parent { }
class Child extends Parent { }
class Brother extends Parent { }
public class Polymorphism01 {
public static void main(String[] args) {
Parent p = new Parent();
System.out.println(p instanceof Object); // true
System.out.println(p instanceof Parent); // true
System.out.println(p instanceof Child); // false
System.out.println();
Parent c = new Child();
System.out.println(c instanceof Object); // true
System.out.println(c instanceof Parent); // true
System.out.println(c instanceof Child); // true
}
}
|
cs |