회원가입

다형성 - 캐스팅

Beany 2024-10-10

ChatGPT 요약

부모 타입 변수로 자식 타입 객체를 사용할 때 다운캐스팅을 해야 자식 타입의 메서드를 사용할 수 있다. 다운캐스팅은 부모 타입을 일시적으로 자식 타입으로 변경하는 것이며, 업캐스팅과 반대이다. 다운캐스팅은 자식 타입에 대입하려는 부모 타입을 자식 타입으로 변경하는 과정으로, 주의가 필요하다. 부모는 자식을 담을 수 있지만 자식은 부모를 담을 수 없다.

캐스팅


Parent poly = new Child() 와 같이 부모 타입의 변수를 사용하게 되면 poly.childMethod() 와 같이 자식 타입에 있는 기능은 호출할 수 없다.

package poly.basic;

public class CastingMain {
    public static void main(String[] args) {
        Parent poly = new Child();
        // ploy.childMethod(); // 컴파일 에러
        
        // 다운캐스팅(부모 타입 -> 자식 타입)
        Child child = (Child) poly;
        child.childMethod();
    }
}
Child method

이렇게 하면 실행이 될 수 있지만 다음과 같은 문제에 봉착한다.

 

부모는 자식을 담을 수 있지만 자식은 부모를 담을 수 없다.

  • Parent parent = new Child(): 부모는 자식을 담을 수 있다.
  • Parent parent = child // CHild child 변수: 부모는 자식을 담을 수 있다.

반면에 다음과 같이 자식은 부모를 담을 수 없다.

Child child = poly // Parent poly 변수

부모 타입을 사용하는 변수를 자식 타입에 대입하려고 하면 컴파일 오류가 발생한다. 자식은 부모를 담을 수 없다. 이때는 다운캐스팅이라는 기능을 사용해서 부모 타입을 잠깐 자식 타입으로 변경하면 된다.

 

다음 코드를 분석해보자.

Child child = (Child) poly  // Parent poly

(타입) 처럼 괄호와 그 사이에 타입을 지정하면 참조 대상을 특정 타입으로 변경할 수 있다. 이렇게 특정 타입으로 변경하는 것을 캐스팅이라 한다.

오른쪽에 있는 (Child) poly 코드를 먼저 보자. poly Parent 타입이다. 이 타입을 (Child) 를 사용해서 일시적으로 자식 타입인 Child 타입으로 변경한다. 그리고 나서 왼쪽에 있는 Child child 에 대입한다.

 

캐스팅

  • 업캐스팅(upcasting): 부모 타입으로 변경
  • 다운캐스팅(downcasting): 자식 타입으로 변경

 

 

 

캐스팅의 종류


자식 타입의 기능을 사용하려면 다음과 같이 다운캐스팅 결과를 변수에 담아두고 이후에 기능을 사용하면 된다.

Child child = (Child) poly;
child.childMethod();

하지만 다운캐스팅 결과를 변수에 담아두는 과정이 번거롭다. 이런 과정 없이 일시적으로 다운캐스팅을 해서 인스턴스에 있는 하위 클래스의 기능을 바로 호출할 수 있다.

 

일시적 다운캐스팅

package poly.basic;

public class CastingMain2 {
    public static void main(String[] args) {
        // 부모 변수가 자식 인스턴스 참조 (다형적 참조)
        Parent poly = new Child();
        // 단 자식의 기능은 호출할 수 없다. 컴파일 에러
        // poly.childMethod();
        
        // 일시적 다운캐스팅 - 해당 메서드를 호출하는 순간만 다운캐스팅
        ((Child) poly).childMethod();
    }
}
Child method

 

업캐스팅

다운캐스팅과 반대로 현재 타입을 부모 타입으로 변경하는 것을 업캐스팅이라 한다.

package poly.basic;

public class CastingMain3 {
    public static void main(String[] args) {
        Child child = new Child();
        Parent parent1 = (Parent) child;  // 업캐스팅은 생략 가능, 생략 권장
        Parent parent2 = child;  // 업캐스팅 생략
        
        parent1.parentMethod();
        parent2.parentMethod();
    }
}
Parent method
Parent method

업캐스팅은 생략할 수 있다. 다운캐스팅은 생략할 수 없다. 참고로 업캐스팅은 매우 자주 사용하기 때문에 생략을 권장한다.

 

 

다운캐스팅과 주의점


다운캐스팅은 잘못하면 심각한 런타임 오류가 발생할 수 있다.

다음 코드를 통해 다운캐스팅에서 발생할 수 있는 문제를 확인해보자.

package poly.basic;

public class CastingMain4 {
    public static void main(String[] args) {
        Parent parent1 = new Child();
        Child child1 = (Child) parent1;
        child1.childMethod();  // 문제 없음
        
        Parent parent2 = new Parent();
        // Child child2 = (Child) parent2;  // 런타임 에러 - ClassCastException
        // child2.childMethod();
    }
}

실행 결과를 보면 child1.childMethod() 는 잘 호출되었지만, child2.childMethod() 는 실행되지 못하고, 그 전에 오류가 발생했다.

Parent parent2 = new Parent();

먼저 new Parent() 로 부모 타입으로 객체를 생성한다. 따라서 메모리 상에 자식 타입은 전혀 존재하지 않는다. 생성 결과를 parent2 에 담아둔다. 이 경우 같은 타입이므로 여기서는 문제가 발생하지 않는다.

Child child2 = (Child) parent2;

다음으로 parent2 Child 타입으로 다운캐스팅한다. 그런데 parent2 Parent로 생성이 되었다. 따라서 메모리 상에 Child 자체가 존재하지 않는다. Child 자체를 사용할 수 없는 것이다.

자바에서는 이렇게 사용할 수 없는 타입으로 다운캐스팅하는 경우에 ClassCastException 이라는 예외를 발생시킨다. 예외가 발생하면 다음 동작이 실행되지 않고, 프로그램이 종료된다. 따라서 child2.childMethod() 코드 자체가 실행되지 않는다.

 

 

업캐스팅이 안전하고 다운캐스팅이 위험한 이유


업캐스팅의 경우 이런 문제가 절대로 발생하지 않는다. 왜냐하면 객체를 생성하면 해당 타입의 상위 부모 타입은 모두 함께 생성된다! 따라서 위로만 타입을 변경하는 업캐스팅은 메모리 상에 인스턴스가 모두 존재하기 때문에 항상 안전하다. 따라서 캐스팅을 생략할 수 있다.

반면에 다운캐스팅의 경우 인스턴스에 존재하지 않는 하위 타입으로 캐스팅하는 문제가 발생할 수 있다. 왜냐하면 객체를 생성하면 부모 타입은 모두 함께 생성되지만 자식 타입은 생성되지 않는다. 따라서 개발자가 이런 문제를 인지하고 사용해야 한다는 의미로 명시적으로 캐스팅을 해주어야 한다.

0 0
JAVA
이 공간은 개인 공부를 통해 얻은 정보를 체계적으로 정리하고 공유하는 곳입니다. 학습한 내용, 발견한 지식, 그리고 문제 해결 방법 등을 기록하여 나만의 학습 자료를 구축하고, 필요할 때 쉽게 참고할 수 있는 유용한 자원으로 활용할 수 있도록 합니다.
Yesterday: 456
Today: 209