앞서 캐스팅에 대해서 포스팅을 해봤다. 이번 포스팅은 저번 포스팅의 연장선이다.
이 두가지의 캐스팅 방법은 OOP에서 클래스 간의 상속 관계에 기반한 타입 변화을 의미한다.
업캐스팅은 어떻게 보면 굉장히 순리적이다. 상위 개념에서 하위 개념의 참조이기 때문이다. 업캐스팅은 부모 클래스의 참조 변수로 자식 클래스의 객체를 참조한다. 업캐스팅은 자동적으로 이루어지며, 따로 타입 캐스팅을 명시적으로 수행할 필요가 없다.
class Animal { }
class Dog extends Animal { }
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // 업캐스팅
}
}
이제 관건은 다운캐스팅이다. 다운캐스팅은 업캐스팅의 반대 개념이다. 부모 클래스의 참조 변수를 사용하여 자식 클래스의 객체를 참조하고자 할 때 사용된다.
class Animal { }
class Dog extends Animal { }
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
// 다운캐스팅
Dog dog = (Dog) animal;
// 또는
if (animal instanceof Dog) {
Dog anotherDog = (Dog) animal;
}
}
}
다운캐스팅 경우 업캐스팅과는 다르게 명시적으로 타입 캐스팅을 해야 하며, 컴파일러나 런타임에서 안전성을 검사한다.
if (animal instanceof Dog) {
Dog anotherDog = (Dog) animal;
}
만약 다운캐스팅을 하려는 객체가 실제로 해당 자식 클래스의 객체가 아니라면 ClassCastException 예외가 발생한다. 따라서 반드시 instanceof 연산자를 사용하여 해당 타입으로 변환 가능한지를 먼저 확인하는 것이 좋다.
업캐스팅 경우에는 데이터 손실 우려가 없다. 하지만, 다운캐스팅 경우에는 데이터 손실이 발생할 수도 있다. 그래서 꼭! 반드시! instanceof 연산자를 사용해야한다.
class Animal { }
class Dog extends Animal {
void bark() { }
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // 업캐스팅
((Dog) animal).bark(); // 다운캐스팅 후 하위 클래스 메소드 호출
}
}
class Shape { }
class Circle extends Shape {
void drawCircle() { }
}
public class Main {
public static void main(String[] args) {
Shape shape = new Circle(); // 업캐스팅
if (shape instanceof Circle) {
Circle circle = (Circle) shape; // 다운캐스팅
circle.drawCircle(); // 하위 클래스 메소드 호출
}
}
}
감사합니다. 이런 정보를 나눠주셔서 좋아요.