객체지향 속성중 하나인 다형성
에 대해서 알아보자. 다형성이란 여러가지 형태를 가질 수 있는 특성을 의미한다. 이는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 하는것을 의미한다.조금 더 구체적으로는 상속관계에서 해당 되는 이야기로, 조상 클래스 타입의 참조변수로 자손클래스 인스턴스를 참조할 수 있도록 하는것이다.
아래 예시를 한번 보자
class TV2{
protected boolean power;
protected int channel;
TV2(){
this.power = false;
this.channel = 0;
}
void power(){
this.power = !this.power;
}
void channelUp(){
++this.channel;
}
void channelDonw(){
--this.channel;
}
}
class CaptionTV2 extends TV2{
private String text;
CaptionTV2(){
super();
}
void caption(){
System.out.println(text);
}
}
class tvtest2{
public static void main(String[] args){
TV2 t = new CaptionTV2();
CaptionTV2 t2 = new CaptionTV2();
t.channelUp();
t2.channelUp();
t.caption(); // 에러가 난다.
t2.caption();
}
}
CaptionTV2 클래스의 인스턴스 두개를 생성하였다. 다만 하나는 참조변수 타입이 TV2이고 하나는 CaptionTV2인것이 차이점이다. 두개다 CaptionTV2
의 인스턴스지만, t
참조변수는 .caption()
메소드를 사용하지 못하는것을 볼 수 있다. 이는 둘다 같은 타입의 인스턴스지만, 참조변수 타입이 달라 접근 및 사용할 수 있는 멤버의 개수가 달라진것이기 때문이다.
자손 타입의 참조변수로 조상타입의 인스턴스를 참조하는것은 존재하지 않는 멤버를 사용하고자 할 가능성이 있으므로 허용하지 않는것이다. 결론적으로 참조변수가 사용할 수 있는 멤버의 개수는 인스턴스 멤버 개수보다 같거나 적어야 한다
위에서 보았던 개념중 t
참조변수는 결국 Up-Casting에 해당 한다. 그렇다면 Down-Casting의 개념은 어떻게 사용될까? 위의 개념만 본다면 아래와 같이 변경해줄 수 있다.
class TV2{
protected boolean power;
protected int channel;
TV2(){
this.power = false;
this.channel = 0;
}
void power(){
this.power = !this.power;
}
void channelUp(){
++this.channel;
}
void channelDonw(){
--this.channel;
}
}
class CaptionTV2 extends TV2{
private String text;
CaptionTV2(){
super();
}
void caption(){
System.out.println(text);
}
}
class tvtest2{
public static void main(String[] args){
TV2 t = new TV2();
CaptionTV2 t2 = (CaptionTV2) t;
t2.caption();
}
}
컴파일은 잘 되는 코드인것을 확인하였다. 하지만 실행을 해보면, 오류가 나는것을 확인할 수 있다. 우선 Down-Casting은 조상클래스 타입 인스턴스를 자식클래스 타입 인스턴스로 변환하는것은 맞다. 하지만, 위 코드에서 t
인스턴스는 처음부터 TV2
클래스의 인스턴스로 생성이 되었다 그렇기 때문에 기본적으로 CaptionTV2
클래스에 있는 .caption()
메소드를 가지고 있지 않다.
결론적으로 Down-Casting은 Up-Casting에 의해 접근범위를 제한당한 인스턴스의 사용 범위를 되돌릴때 사용한다. 이를 사용할때 instanceof
연산자와 같이 사용하여 더욱 안전하게 Down-Casting을 진행해 줄 수 있다.
class TV2{
protected boolean power;
protected int channel;
TV2(){
this.power = false;
this.channel = 0;
}
void power(){
this.power = !this.power;
}
void channelUp(){
++this.channel;
}
void channelDonw(){
--this.channel;
}
}
class CaptionTV2 extends TV2{
private String text;
CaptionTV2(String text){
super();
this.text = text;
}
void caption(){
System.out.println(text);
}
}
class tvtest2{
public static void main(String[] args){
TV2 t = new CaptionTV2("Example text");
CaptionTV2 t2;
if(t instanceof CaptionTV2){
t2 = (CaptionTV2) t; // DownCasting은 형변환 생략이 불가능하다
t2.caption();
}
}
}