본문 바로가기
Tutorial/Java

자바(Java)에서 업캐스팅(Upcasting)과 다운캐스팅(Downcasting) 이해하기

by CLJ 2024. 5. 20.

자바(Java)는 객체 지향 프로그래밍 언어로, 다형성(polymorphism)을 통해 객체를 다양한 형태로 다룰 수 있습니다. 이러한 다형성을 효과적으로 활용하기 위해 자주 사용되는 개념이 바로 업캐스팅(Upcasting)과 다운캐스팅(Downcasting)입니다.
 

업캐스팅 (Upcasting)

 
업캐스팅은 자식 클래스의 객체를 부모 클래스 타입으로 변환하는 것을 말합니다. 업캐스팅은 암시적(implicit)으로 이루어지며, 명시적(explicit)인 캐스팅이 필요하지 않습니다. 암시적이라는 것은 별도의 캐스팅 연산자 없이 자동으로 수행된다는 의미입니다. 주로 상속 관계에서 부모 클래스의 메서드를 재정의(오버라이딩)한 자식 클래스의 메서드를 호출하기 위해 사용됩니다.
 
다음은 업캐스팅의 예시 코드입니다. Animal클래스에 sound() 메서드가 있습니다. 그리고 Dog클래스는 선언부에 "extends Animal"이 있기 때문에 Animal을 상속받고 있습니다. Animal이 부모클래스이고 Dog는 자식 클래스가 됩니다. 

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    void sound() {
        System.out.println("Dog barks");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog(); // 업캐스팅
        myDog.sound(); // "Dog barks" 출력
    }
}

 
위 코드의 메인 클래스에서 Dog 객체가 Animal 타입으로 업캐스팅되었습니다. myDog 변수가 Animal 타입이지만, 실제로는 Dog 객체를 참조하고 있으므로 Dog 클래스의 sound() 메서드가 호출됩니다.
 

다운캐스팅 (Downcasting)

 
다운캐스팅은 부모 클래스 타입의 객체를 자식 클래스 타입으로 변환하는 것을 말합니다. 이는 명시적(explicit)으로 이루어져야 하며, 잘못된 다운캐스팅은 ClassCastException 에러를 발생시킬 수 있습니다. 명시적이라는 것은 캐스팅 연산자를 사용하여 명확하게 타입 변환을 지시하는 것을 의미합니다. 다운캐스팅은 업캐스팅된 객체를 다시 원래의 자식 클래스 타입으로 돌려놓을 때 사용됩니다.  
 
다음은 다운캐스팅의 예시 코드입니다. 부모클래스 Animal에서는 sound()메소드를 포함하고 있고, 자식클래스 Dog는 sound()메서드를 오버라이딩했고, fetch()메서드를 가지고 있습니다. 

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    void sound() {
        System.out.println("Dog barks");
    }

    void fetch() {
        System.out.println("Dog fetches");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal myAnimal = new Dog(); // 업캐스팅
        myAnimal.sound(); // "Dog barks" 출력

        // 다운캐스팅을 통해 Dog 클래스의 fetch() 메서드 호출
        if (myAnimal instanceof Dog) {
            Dog myDog = (Dog) myAnimal; // 다운캐스팅
            myDog.fetch(); // "Dog fetches" 출력
        }
    }
}


위의 메인클래스에서 myAnimal은 Dog 타입의 객체를 참조하는 Animal 타입 변수입니다. 이렇게 업캐스팅된 myAnimal은 Animal타입이기 때문에 Animal 클래스에 정의된 메서드만 호출할 수 있습니다. myAnimal.sound()는 Animal 클래스에 정의된 메서드이므로 호출이 가능하지만 실제로는 Dog객체를 참조하기 때문에 실행되는 메서드는 Dog클래스에서 오버라이딩된 sound() 메서드입니다. 자식 클래스에 추가된 메서드 또는 필드는 접근할 수 없습니다.

fetch() 메서드는 Animal클래스에 정의되지 않았기 때문에 호출할 수 없습니다. 호출하면, 컴파일 오류를 발생시킵니다. 이를 해결할 수 있는 방법이 다운캐스팅입니다. 다운캐스팅할 때에는 instanceof 연산자를 사용하여 안전하게 타입을 확인합니다. 위의 코드에서도 myAnimal이 Dog의 인스턴스인지 확인한 후에 다운캐스팅을 통해 myAnimal을 Dog 타입으로 변환하여 Dog 클래스에만 정의된 fetch() 메서드를 호출하고 있습니다. 
 
업캐스팅은 객체 생성할 때와 인스턴스를 변수에 대입할 때 둘다 가능하지만, 다운캐스팅은 후자(인스턴스을 변수에 대입하는 경우)만 가능합니다. 
 

활용 및 주의 사항

 
업캐스팅은 다형성을 구현하는데 필수적입니다. 이를 통해 하나의 인터페이스나 부모 클래스가 다양한 자식 클래스의 구현을 받을 수 있습니다. 업캐스팅은 주로 런타임에 어떤 메서드가 호출될지를 결정하는 다형성(polymorphism)을 구현하는데 사용됩니다. 또한 업캐스팅과 다운캐스팅을 적절히 사용하면 코드의 유연성과 재사용성을 높일 수 있습니다. 
 
업캐스팅된 객체를 다시 다운캐스팅할 때는 원래 타입을 정확히 알고 있어야 합니다. 잘못된 다운캐스팅은 ClassCastException을 발생시킬 수 있으므로, 항상 instanceof를 사용하여 안전하게 캐스팅 가능 여부를 확인해야 합니다. 
 

결론

 
업캐스팅과 다운캐스팅은 Java에서 다형성을 구현하고 객체를 유연하게 다루기 위한 중요한 기법입니다. 업캐스팅은 암시적으로 이루어지며, 다운캐스팅은 명시적으로 이루어집니다. 이를 통해 코드의 유연성과 재사용성을 높일 수 있으며, 런타임 다형성을 효과적으로 활용할 수 있습니다.

업캐스팅 후에는 부모클래스 타입의 참조 변수로 자식 클래스에서 추가된 메서드나 필드에 접근할 수 없습니다.

자식 클래스의 메서드에 접근하려면 다운캐스팅을 통해 자식 클래스 타입으로 변환해야 합니다. 업캐스팅과 다운캐스팅을 올바르게 이해하고 사용함으로써, 더 견고하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.