캐스팅이란 무엇일까?

캐스팅(casting)이란 타입을 변환하는 것을 말하며 형변환이라고도 한다. 자바의 상속 관계에 있는 부모와 자식 클래스 간에는 서로 간의 형변환이 가능하다.

 

이번 글에서는 자식 클래스가 부모 클래스의 타입으로 캐스팅되는 업캐스팅과 반대로 부모 클래스가 자식 클래스의 타입으로 캐스팅되는 다운캐스팅에 대해서 알아본다. 시작하기에 앞서 부모 클래스인 상속 관계의 상위 클래스를 수퍼 클래스, 그리고 자식 클래스인 하위 클래스를 서브 클래스라고 정의한다.


업캐스팅

자바에서 서브 클래스는 수퍼 클래스의 모든 특성을 상속받는다. 그렇기 때문에 서브 클래스는 수퍼 클래스로 취급될 수 있다. 여기서 업캐스팅(Upcasting)이란 서브 클래스의 객체가 수퍼 클래스 타입으로 형변환되는 것을 말한다.

 

즉, 수퍼 클래스 레퍼런스 변수가 서브 클래스로 객체화된 인스턴스를 가리킬 수 있게 된다. 더 쉽게 풀어서 예시를 들어보면 사람은 생물이다라고 생각하면 된다. 여기서 사람은 서브 클래스이고 생물은 수퍼 클래스다.

 

위의 코드에서처럼 업캐스팅 시에는 아래와 같이 명시적인 타입 캐스팅 선언을 하지 않아도 된다.

서브 클래스 Student는 Person 타입이기 때문에도 그렇다.


다운캐스팅

다운캐스팅(Downcasting)은 자신의 고유한 특성을 잃은 서브 클래스의 객체를 다시 복구 시켜주는 것을 말한다. 그러니까 업캐스팅된 것을 다시 원상태로 돌리는 것을 말한다.

 

여기서 업캐스팅과 다른 점은 명시적으로 타입을 지정해야 한다는 점이다. 그리고 업캐스팅이 선행이 되어야 한다. 다운캐스팅을 하면서 형변환할 대상을 지정했지만 무분별한 다운캐스팅은 컴파일 시점에는 오류가 발생하지 않아도 런타임 오류를 발생시킬 가능성이 있다.

 

예를 들어 아래와 같이 진행하는 경우는 실행중 오류가 발생한다.

따라서 형변환할 타입을 명시함으로서 컴파일 오류는 사라졌지만 실제 코드를 수행하면 ClassCastException이 발생하게 된다. 한편 이렇게 혼동되는 객체를 구별하기 위해 도움을 주는 연산자가 있다.


instanceof

객체의 타입을 구분하기 위해 instanceof 연산자를 사용할 수 있다.

예를 들어 업캐스팅을 했을 때 레퍼런스 변수가 가리키는 객체의 타입이 어떤 것인지 구분하기 어려울 때 유용하다.

아래와 같이 상속 관계를 갖는 클래스들이 있다고 가정해보자.

 

예제로 만든 클래스 Zealot, Marine, Zergling은 모두 Unit 클래스를 상속하고 있다.

따라서 위 코드에서의 업캐스팅 코드는 컴파일 오류없이 정상적으로 수행된다.

 

한편 unit 레퍼런스 변수가 어떤 객체를 가리키고 있다고 가정할 때 가리키는 객체의 실제 클래스 타입을 구분하려면 어떻게 해야할까?

만일 아래와 같은 메서드가 있다면 파라미터로 어떤 타입의 객체가 넘어오는지 알 수 있을까?

 

앞서 언급한 instanceof 연산자를 사용하면 객체의 타입을 쉽게 구별할 수 있다. 연산의 결과 타입은 boolean이며 아래와 같이 이항연산자처럼 사용하면 된다.

class Unit {
    // 생략
}

class Zealot extends Unit {
    // 생략
}

class Marine extends Unit {
    // 생략
}

class Zergling extends Unit {
    // 생략
}

public class CastingTest {
    public static void main(String[] args) {
        Unit unit1 = new Unit();
        Unit unit2 = new Zealot(); // 업캐스팅
        Unit unit3 = new Marine(); // 업캐스팅
        Unit unit4 = new Zergling(); // 업캐스팅

        if (unit1 instanceof Unit) { // true
            System.out.println("unit1은 Unit 타입이다.");
        }
        if (unit1 instanceof Zealot) { // false
            System.out.println("unit1은 Zealot 타입이다.");
        }
        if (unit2 instanceof Zealot) { // true
            System.out.println("unit2는 Zealot 타입이다.");
        }
        if (unit2 instanceof Zergling) { // false
            System.out.println("unit2는 Zergling 타입이다.");
        }
        if (unit3 instanceof Unit) { // true
            System.out.println("unit3은 Unit 타입이다.");
        }
        if (unit4 instanceof Zergling) { // false
            System.out.println("unit4는 Zergling 타입이다");
        }
    }
}  

 

객체가 실제로 어떤 타입인지 비교할 수 있다.

실행 시점에 발생할 수 있는 형변환 오류를 줄일 수 있는 것이다.

java.lang.String 클래스의 equals 메서드를 보면 아래와 같이 구현되어 있다.

최상위 Object 객체를 파라미터로 받되, 실제로 자신과 값을 비교할 수 있는 String 타입인지 확인한다.

'📌 java > Object-oriented Programming' 카테고리의 다른 글

Homework_8  (0) 2020.05.07
Homework_W7 (상속 ≠ 오버라이딩)  (0) 2020.05.02
java - 상속의 참조 관계  (0) 2020.04.26
Homework_W6  (0) 2020.04.23
Homework_W5  (0) 2020.04.14
복사했습니다!