Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java 형 변환 완벽 가이드: 확장 캐스팅(암시적)과 축소 캐스팅(명시적)의 차이점

Java에서 형 변환(Type Casting)은 한 타입의 객체나 변수를 다른 타입으로 변환할 때 사용됩니다. 한 데이터 타입을 다른 타입으로 변환하거나 할당할 때 두 타입이 서로 호환되지 않을 수 있으며, 호환된다면 자연스럽게 변환이 이루어지지만 그렇지 않은 경우에는 데이터 손실이 발생할 가능성이 있습니다.

Java 형 변환의 종류

Java의 형 변환은 크게 두 가지로 분류됩니다.

  • 확장 캐스팅(Widening Casting, 암시적) – 자동 타입 변환
  • 축소 캐스팅(Narrowing Casting, 명시적) – 명시적인 변환 필요

확장 캐스팅 (작은 타입 → 큰 타입)

확장 형 변환(Widening Type Conversion)은 두 타입이 서로 호환되고 대상 타입이 원본 타입보다 클 때 발생합니다. 즉, 두 타입이 호환되며 대상 타입이 원본 타입보다 큰 경우에 적용되며, 개발자가 별도로 캐스팅 연산자를 작성하지 않아도 컴파일러가 자동으로 변환을 처리해 줍니다.

예제 1: 기본 타입의 확장 캐스팅

public class ImplicitCastingExample {
    public static void main(String args[]) {
        byte i = 40;
        // 아래 변환에는 캐스팅이 필요 없음
        short j = i;
        int k = j;
        long l = k;
        float m = l;
        double n = m;
        System.out.println("byte value : " + i);
        System.out.println("short value : " + j);
        System.out.println("int value : " + k);
        System.out.println("long value : " + l);
        System.out.println("float value : " + m);
        System.out.println("double value : " + n);
    }
}

실행 결과

byte value : 40
short value : 40
int value : 40
long value : 40
float value : 40.0
double value : 40.0

위 예제에서 볼 수 있듯이 byte → short → int → long → float → double 순서로 작은 타입에서 큰 타입으로 변환될 때는 어떠한 캐스팅 연산자 없이도 값이 안전하게 전달됩니다.

클래스 타입의 확장 캐스팅

형 변환은 기본 타입뿐만 아니라 클래스 타입에도 적용됩니다. 아래 예제에서는 Child 클래스(작은 타입)의 인스턴스를 Parent 클래스(큰 타입) 변수에 할당하고 있습니다. 자식 클래스는 부모 클래스보다 하위 타입이므로 업캐스팅(upcasting) 시 캐스팅 연산자가 필요하지 않습니다.

예제 2: 클래스 타입의 확장 캐스팅

class Parent {
    public void display() {
        System.out.println("Parent class display() called");
    }
}
public class Child extends Parent {
    public static void main(String args[]) {
        Parent p = new Child();
        p.display();
    }
}

실행 결과

Parent class display() method called

축소 캐스팅 (큰 타입 → 작은 타입)

반대로 큰 타입을 작은 타입에 할당할 때는 명시적 캐스팅(Explicit Casting)이 반드시 필요합니다. 축소 캐스팅 시에는 데이터 손실이 발생할 수 있으므로 컴파일러가 자동으로 변환해 주지 않으며, 개발자가 직접 캐스팅 연산자를 명시해야 합니다.

예제 1: 기본 타입의 축소 캐스팅

public class ExplicitCastingExample {
    public static void main(String args[]) {
        double d = 30.0;
        // 아래 변환에는 명시적 캐스팅이 필요함
        float f = (float) d;
        long l = (long) f;
        int i = (int) l;
        short s = (short) i;
        byte b = (byte) s;
        System.out.println("double value : " + d);
        System.out.println("float value : " + f);
        System.out.println("long value : " + l);
        System.out.println("int value : " + i);
        System.out.println("short value : " + s);
        System.out.println("byte value : " + b);
    }
}

실행 결과

double value : 30.0
float value : 30.0
long value : 30
int value : 30
short value : 30
byte value : 30

double에서 byte로 갈수록 타입의 크기가 줄어들기 때문에 매 단계마다 (float), (long), (int)와 같은 캐스팅 연산자를 반드시 붙여야 합니다.

클래스 타입의 축소 캐스팅

클래스 타입에서도 마찬가지로 큰 타입(부모 클래스)을 작은 타입(자식 클래스)에 할당할 때는 명시적 캐스팅, 즉 다운캐스팅(downcasting)이 필요합니다.

예제 2: 클래스 타입의 축소 캐스팅

class Parent {
    public void display() {
        System.out.println("Parent class display() method called");
    }
}
public class Child extends Parent {
    public void display() {
        System.out.println("Child class display() method called");
    }
    public static void main(String args[]) {
        Parent p = new Child();
        Child c = (Child) p;
        c.display();
    }
}

실행 결과

Child class display() method called

정리: 확장 캐스팅 vs 축소 캐스팅

구분확장 캐스팅 (암시적)축소 캐스팅 (명시적)
변환 방향작은 타입 → 큰 타입큰 타입 → 작은 타입
캐스팅 연산자불필요 (자동 변환)필요 (직접 명시)
데이터 손실없음발생 가능
클래스 관점업캐스팅 (자식 → 부모)다운캐스팅 (부모 → 자식)

핵심을 요약하면, 작은 타입에서 큰 타입으로의 변환은 컴파일러가 안전하다고 판단하여 자동으로 처리해 주지만, 큰 타입에서 작은 타입으로의 변환은 데이터 손실 위험이 있기 때문에 반드시 개발자가 명시적으로 캐스팅해 주어야 합니다. 특히 클래스 타입의 다운캐스팅은 실제 객체가 해당 타입이 아닐 경우 ClassCastException이 발생할 수 있으므로, 필요하다면 instanceof 연산자로 타입을 확인한 후 캐스팅하는 것이 안전합니다.