Java를 공부하다 보면 반드시 마주치는 개념 중 하나가 "형변환(casting)"입니다. 기본형(primitive type)에서도 형변환은 자주 사용되지만, 이번 글에서는 참조형(reference type)의 형변환에 초점을 맞춰 정리해 보겠습니다.
기본형처럼 참조형도 형변환이 가능합니다. 하지만 참조형의 형변환은 오직 상속 관계가 있는 클래스 사이에서만 허용됩니다. 즉,
자손 타입 → 조상 타입: ✅ 가능 (자동 형변환, upcasting)
조상 타입 → 자손 타입: ✅ 가능 (명시적 형변환, downcasting)
상속 관계가 없는 타입 간의 형변환: ❌ 불가능
다음 코드를 보면서 이해해 봅시다:
class Main {
public static void main(String args[]) {
Car car = null;
FireEngine fe = new FireEngine(); // 자손 클래스 객체 생성
FireEngine fe2 = null;
fe.water(); // 자손 클래스의 메서드 호출
car = fe; // 🔼 Upcasting (자동 형변환)
fe2 = (FireEngine) car; // 🔽 Downcasting (명시적 형변환)
fe2.water(); // 다시 자손 메서드 호출 가능
}
}
class Car {
String color;
int door;
void drive() {
System.out.println("drive, Brrrr~");
}
void stop() {
System.out.println("stop!!!");
}
}
class FireEngine extends Car {
void water() {
System.out.println("water!!!");
}
}
fe는 FireEngine 인스턴스를 가리킴.
car = fe; → FireEngine 인스턴스를 Car 타입 참조 변수로 참조.
car는 FireEngine의 인스턴스를 참조하고 있지만 Car 타입이므로 water() 메서드는 호출할 수 없음.
다시 형변환하여 fe2 = (FireEngine) car; → water() 호출 가능.
참조형의 형변환은 참조 변수의 타입만 바꾸는 것입니다. 실제 인스턴스(객체)는 변하지 않고 그대로 존재합니다.
Java에서 모든 클래스는 Object를 상속받기 때문에, 모든 참조 변수는 Object 타입으로 형변환이 가능합니다.
FireEngine fe = new FireEngine();
Object obj = fe; // 가능
| 형변환 방향 | 생략 가능 여부 | 예시 |
|---|---|---|
| 자손 → 조상 (Upcasting) | ✅ 생략 가능 | Car car = new FireEngine(); |
| 조상 → 자손 (Downcasting) | ❌ 생략 불가 | FireEngine fe = (FireEngine) car; |
instanceof 는 형변환 전에 객체의 실제 타입을 확인할 수 있게 해줍니다. Downcasting 하기 전에는 반드시 instanceof로 확인하는 습관을 들이는 것이 좋습니다.
if (car instanceof FireEngine) {
FireEngine fe = (FireEngine) car;
fe.water();
}
instanceof 는 실제 인스턴스가 해당 타입이거나 그 자손인지를 확인합니다.| 항목 | 설명 |
|---|---|
| 형변환 대상 | 상속 관계가 있는 클래스 간에만 가능 |
| Upcasting | 자손 → 조상, 생략 가능 |
| Downcasting | 조상 → 자손, 생략 불가 |
| 실제 객체는 변하는가? | ❌ 변하지 않음 |
| 형변환 전 타입 확인 방법 | instanceof 사용 |
| 모든 참조형의 조상 | Object |
참조형의 형변환은 다형성(polymorphism) 개념과 함께 Java 객체지향 프로그래밍의 중요한 기초입니다. 복잡한 상속 구조에서 객체를 다룰 때 형변환과 instanceof의 활용은 코드의 안정성과 유연성을 크게 높여줍니다.
👉 꼭 기억하세요:
참조 변수의 타입과 인스턴스의 타입은 일치하지 않을 수 있다.