본문 바로가기
java

자바의 다형성

by 킹차니 2021. 3. 25.

자바의 다형성에 대한 이해가 부족해서 다시 공부하고 나중에 또 까먹을까봐 다시 정리해둔다.

 

다형성: 여러가지 형태를 가질 수 있는 능력.

더 구체적으로 : 조상클래스의 타입의 참조 변수로 자손 클래스의 인스턴스를 참조할 수 있다.

 

특정 클래스가 다른 클래스를 상속받으면 이는 자식클래스와 부모클래스의 관계를 가진다.

여기서 무조건! 자식 클래스는 부모 클래스보다 같거나 더 많은 멤버를 가진다

 

그런데 만약 참조변수는 부모클래스 타입으로 하고, 인스턴스는 자손 클래스 타입으로 생성한다면?

이것이 다형성이다. 즉 부모 클래스의 참조변수가 자식 클래스의 인스턴스를 참조할 수 있다.

 

모든 클래스의 부모인 Object클래스와 내가 정의한 PolyTest 클래스를 예로 들어보자 (내가 정의하던 누가 정의하던 모든 클래스는 Object클래스의 자손이다.)

class Polytest{
	public void polyMethod(){
    	System.out.println("poly poly");
    }
}
public class Test{
	public static void main(String[] args){
    
    	Object obj = new PolyTest(); //부모클래스 타입 참조변수가 자식클래스 인스턴스 참조
        
        //obj.polyMethod();    에러!!!!
    }
}

 

그런데 저렇게 부모클래스타입 참조변수가 자식클래스타입의 인스턴스를 참조하게 되면 obj는

PolyTest 클래스의 인스턴스를 참조하고 있음에도 PolyTest의 메소드 polyMethod()에 접근 할 수 없다.

왜냐하면 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다!

 

(물론 자식의 오버라이딩된 메소드는 접근할 수 있지만 여기서는 다루지 않는다.)

 

즉 자식클래스 인스턴스를 부모클래스 타입의 참조변수가 참조하는 것은 일종의 가림막이 생기게 되는 것이다.

=>>>> 참조변수의 타입에 따라서 사용할 수 있는 멤버변수의 개수가 달라진다.

=>>>> 참조변수.멤버 이런식으로 접근하므로 참조변수가 멤버에 접근하는 범위를 결정한다.

 

그렇다면 반대는 가능할까? 즉

PolyTest poly = new Object();

위처럼 자식클래스 타입의 참조변수로 부모클래스 타입의 인스턴스를 참조할 수 있을까?

이것은  불가능하다.

 

 

형변환

 

부모 -> 자식

자식 -> 부모

요렇게 참조변수의 형변환이 가능하다.

여기서  자식 -> 부모  의 형변환은 업캐스팅이라고 한다. 이는 형변환을 생략할 수 있다.

 

위에서 강조한 것처럼 << 참조변수가 멤버에 접근하는 범위를 결정하기 때문이다. >>

자식 -> 부모로 참조변수형이 변환된다면 변환된 참조변수는 호출할 수 있는 멤버의 개수가 더 적어지는 것이다.

class Polytest{
	public void polyMethod(){
    	System.out.println("poly poly");
    }
}
public class Test{
	public static void main(String[] args){
    
    	Object obj = new Object();
        PolyTest poly = new PolyTest();
        
       	obj = poly;   //업캐스팅. obj = (Object)poly; 와 같다.
    }
}

부모가 1, 2, 3을 가지고 있고,  자식클래스가 1, 2, 3, 4, 5를 가지고 있다면 

부모클래스형 참조변수로 변하기 전의 참조변수는  1, 2, 3, 4, 5에 접근할 수 있었다. 그런데

부모클래스형 참조변수로 형변환되면 1, 2, 3에만 접근할 수 있다. 가림막이 생기니까!

(다시 강조: 참조변수가 멤버에 접근하는 범위를 결정 )

이것은 문제 될 것이 없다. 1 , 2, 3, 4, 5모두를 호출할 수 있는 친구가

1 , 2, 3을 호출 못할 일은 없으니까.

 

그런데 반대로 부모 -> 자식으로 형변환될 때는 명시를 해줘야한다.

class Polytest{
	public void polyMethod(){
    	System.out.println("poly poly");
    }
}
public class Test{
	public static void main(String[] args){
    
    	Object obj = new Object();
        PolyTest poly = new PolyTest();
        
       	poly = (PolyTest)obj;   // 업캐스팅
    }
}

코드를 보면 (PolyTest)로 형변환을 하는 것을 알 수 있다.

왜냐하면 obj가 PolyTest형(자식클래스형) 참조변수가 되면 더 많은 기능에 접근할 수 있는 발판?을 가지게 된다.

즉 4, 5에 접근을 못하게 하던 가림막이 없어지는 것이다.

 

하지만 물론 위의 코드에서 처럼 애초에 Object형 인스턴스 였던 obj가 가림막이 사라진다해서 PolyTest의 기능을 쓸 수 있는 것은 아니다.

class Polytest{
	public void polyMethod(){
    	System.out.println("poly poly");
    }
}
public class Test{
	public static void main(String[] args){
    
    	Object obj = new Object();
        PolyTest poly = new PolyTest();
        
       	poly = (PolyTest)obj;   // 업캐스팅
        
        obj.polyMethod();  // 컴파일 시에는 에러 안난다. 실행하면 에러!!!
    }
}

위의 코드처럼 실행을 하면 에러가 난다. 왜냐하면 obj의 인스턴스는 Object형이고 Object클래스에는 polyMethod()라는 메소드가 없다.....

 

이 불편해 보이는 관계를 통해서 다형성을 구현하면 좋은 객체지향 프로그래밍을 할 수 있다.

그것을 배우기 전에 이해하기 위해 기록.