본문 바로가기
Java

Java | 업캐스팅과 다운캐스팅

by sseul-log 2025. 10. 2.

목차

  1. 업캐스팅(Upcasting)이란?
  2. 다운캐스팅(Downcasting)이란?
  3. instanceof 연산자
  4. 실전 예제
  5. 자주 하는 실수와 해결방법

1. 업캐스팅(Upcasting)이란?

정의

자식 클래스 객체를 부모 클래스 타입으로 참조하는 것

기본 예제

java
// 부모 클래스
class Animal {
    void eat() {
        System.out.println("동물이 먹습니다");
    }
    
    void sleep() {
        System.out.println("동물이 잡니다");
    }
}

// 자식 클래스
class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("강아지가 사료를 먹습니다");
    }
    
    void bark() {  // Dog만의 고유 메서드
        System.out.println("멍멍!");
    }
}

public class Main {
    public static void main(String[] args) {
        // 일반적인 객체 생성
        Dog myDog = new Dog();
        myDog.eat();   // "강아지가 사료를 먹습니다"
        myDog.bark();  // "멍멍!"
        
        // 업캐스팅 (자동 형변환)
        Animal myAnimal = new Dog();  // Dog → Animal
        myAnimal.eat();    // "강아지가 사료를 먹습니다" (오버라이딩된 메서드)
        myAnimal.sleep();  // "동물이 잡니다"
        // myAnimal.bark(); // 컴파일 에러! Animal에는 bark()가 없음
    }
}

업캐스팅의 특징

  • 자동 형변환: 명시적 캐스팅 불필요
  • 안전한 변환: 항상 성공 (자식은 부모의 모든 것을 포함)
  • 메서드 제한: 부모 클래스에 정의된 메서드만 호출 가능
  • 실제 객체 유지: 메모리의 실제 객체는 여전히 자식 클래스

메모리 구조

업캐스팅 전후 비교:

[업캐스팅 전]
Dog myDog = new Dog();
    ↓
참조변수: Dog 타입
실제객체: Dog 객체
접근가능: eat(), sleep(), bark() ✅

[업캐스팅 후]
Animal myAnimal = new Dog();
    ↓
참조변수: Animal 타입
실제객체: Dog 객체 (변하지 않음!)
접근가능: eat(), sleep() ✅  bark() ❌

2. 다운캐스팅(Downcasting)이란?

정의

부모 클래스 타입을 자식 클래스 타입으로 변환하는 것

주의사항

  • 명시적 캐스팅 필요
  • 위험할 수 있음 (ClassCastException 발생 가능)
  • instanceof로 체크 필수

다운캐스팅 예제

java
public class CastingExample {
    public static void main(String[] args) {
        // 1. 업캐스팅
        Animal animal = new Dog();  // Dog 객체를 Animal로 참조
        animal.eat();  // OK
        // animal.bark(); // 컴파일 에러
        
        // 2. 다운캐스팅 (명시적 형변환 필요)
        Dog dog = (Dog) animal;  // Animal → Dog
        dog.bark();  // "멍멍!" - 이제 사용 가능!
        
        // 3. 잘못된 다운캐스팅 (런타임 에러)
        Animal pureAnimal = new Animal();
        // Dog wrongDog = (Dog) pureAnimal;  // ClassCastException!
        
        // 4. 안전한 다운캐스팅 (instanceof 사용)
        if (animal instanceof Dog) {
            Dog safeDog = (Dog) animal;
            safeDog.bark();  // 안전하게 실행
        }
    }
}

3. instanceof 연산자

instanceof란?

객체가 특정 클래스의 인스턴스인지 확인하는 연산자

 
 
java
public class InstanceOfExample {
    static void checkAnimal(Animal animal) {
        // 다운캐스팅 전 반드시 체크!
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.bark();
        } else if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.meow();
        } else {
            System.out.println("일반 동물입니다");
        }
    }
    
    public static void main(String[] args) {
        checkAnimal(new Dog());     // "멍멍!"
        checkAnimal(new Cat());     // "야옹~"
        checkAnimal(new Animal());  // "일반 동물입니다"
    }
}

4. 실전 예제

게임 캐릭터 시스템

java
// 기본 캐릭터 클래스
abstract class Character {
    protected String name;
    protected int hp;
    
    public Character(String name, int hp) {
        this.name = name;
        this.hp = hp;
    }
    
    abstract void attack();
    
    void move() {
        System.out.println(name + "이(가) 이동합니다");
    }
}

// 전사 클래스
class Warrior extends Character {
    private int armor;
    
    public Warrior(String name) {
        super(name, 200);
        this.armor = 50;
    }
    
    @Override
    void attack() {
        System.out.println(name + "이(가) 검으로 공격!");
    }
    
    void shieldBlock() {  // 전사만의 스킬
        System.out.println(name + "이(가) 방패로 막기!");
    }
}

// 마법사 클래스
class Wizard extends Character {
    private int mana;
    
    public Wizard(String name) {
        super(name, 100);
        this.mana = 200;
    }
    
    @Override
    void attack() {
        System.out.println(name + "이(가) 마법 공격!");
    }
    
    void castSpell() {  // 마법사만의 스킬
        System.out.println(name + "이(가) 화염구 발사!");
    }
}

// 게임 매니저
public class GameManager {
    // 모든 캐릭터를 관리하는 배열 (업캐스팅 활용)
    private Character[] characters = new Character[10];
    private int count = 0;
    
    // 캐릭터 추가 (업캐스팅 자동 발생)
    void addCharacter(Character character) {
        characters[count++] = character;
    }
    
    // 모든 캐릭터 공격
    void allAttack() {
        for (int i = 0; i < count; i++) {
            characters[i].attack();  // 각자의 방식으로 공격
        }
    }
    
    // 특정 스킬 사용 (다운캐스팅 필요)
    void useSpecialSkill(int index) {
        Character character = characters[index];
        
        if (character instanceof Warrior) {
            Warrior warrior = (Warrior) character;  // 다운캐스팅
            warrior.shieldBlock();
        } else if (character instanceof Wizard) {
            Wizard wizard = (Wizard) character;  // 다운캐스팅
            wizard.castSpell();
        }
    }
    
    public static void main(String[] args) {
        GameManager gm = new GameManager();
        
        // 다양한 캐릭터 추가 (업캐스팅)
        gm.addCharacter(new Warrior("아서"));
        gm.addCharacter(new Wizard("멀린"));
        gm.addCharacter(new Warrior("란슬롯"));
        
        // 모든 캐릭터 공격
        gm.allAttack();
        // 출력:
        // 아서이(가) 검으로 공격!
        // 멀린이(가) 마법 공격!
        // 란슬롯이(가) 검으로 공격!
        
        // 특수 스킬 사용
        gm.useSpecialSkill(0);  // 아서이(가) 방패로 막기!
        gm.useSpecialSkill(1);  // 멀린이(가) 화염구 발사!
    }
}

5. 자주 하는 실수와 해결방법

❌ 실수 1: instanceof 체크 없이 다운캐스팅

 
java
// 잘못된 코드
Animal animal = new Animal();
Dog dog = (Dog) animal;  // ClassCastException!

// 올바른 코드
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    // 안전하게 사용
}

❌ 실수 2: 업캐스팅 후 자식 메서드 호출 시도

java
// 잘못된 코드
Animal animal = new Dog();
animal.bark();  // 컴파일 에러!

// 해결방법 1: 다운캐스팅
Dog dog = (Dog) animal;
dog.bark();

// 해결방법 2: 처음부터 자식 타입으로 선언
Dog dog = new Dog();
dog.bark();

❌ 실수 3: 형제 클래스 간 캐스팅 시도

java
class Cat extends Animal { }
class Dog extends Animal { }

// 잘못된 코드
Cat cat = new Cat();
Dog dog = (Dog) cat;  // 컴파일 에러! Cat과 Dog는 형제 관계

// 올바른 방법: 공통 부모를 통한 처리
Animal animal1 = new Cat();
Animal animal2 = new Dog();

업캐스팅 vs 다운캐스팅 비교

구분 업캐스팅 다운캐스팅
방향 자식 → 부모 부모 → 자식
형변환 자동 (암묵적) 명시적 필요
안전성 항상 안전 위험할 수 있음
instanceof 불필요 필수 권장
사용 시기 다형성 구현 자식 고유 기능 필요시
예시 Animal a = new Dog() Dog d = (Dog) animal

핵심 정리

업캐스팅

  • 자동 형변환으로 안전하게 부모 타입으로 변환
  • 다형성의 핵심 메커니즘
  • 부모 클래스의 메서드만 호출 가능

다운캐스팅

  • 명시적 형변환 필요
  • instanceof로 안전성 체크 필수
  • 자식 클래스의 고유 메서드 사용 가능

실무 팁

  1. 가능한 업캐스팅을 활용한 다형성 설계
  2. 다운캐스팅은 꼭 필요한 경우만 사용
  3. instanceof 체크를 습관화
  4. 인터페이스와 추상 클래스를 활용한 설계