기록공간

클래스 고급 - 클래스 캐스팅 본문

Java

클래스 고급 - 클래스 캐스팅

입코딩 2020. 8. 25. 21:54
반응형

캐스팅은 '(자료형)'을 사용하며 자료형을 명시적으로 변환시켜주는 작업을 한다. 하지만 이를 기본 자료형이 아닌 클래스에서 사용하면 업 캐스팅다운 캐스팅을 할 수 있다.

 

그럼 업, 다운 캐스팅이 무엇이며 어떻게 쓰는지 알아보도록 하겠다.

 

예제)

// super class, 부모 클래스, 상위 클래스
class Super
{
	public int a = 10, b = 20;

	public void write()
	{
		System.out.println("슈퍼 클래스 write() 메소드...");
	}

	public int hap()
	{
		return a + b;
	}
}

// sub class, 자식 클래스, 하위 클래스
class Sub extends Super
{
	public int b = 100, c = 200;

	@Override
	public int hap()
	{
		return a + b + c;
	}

	public void print()
	{
		System.out.println("서브 클래스 print() 메소드...");
	}
}

 위 코드는 상위 클래스 Super와 그 클래스를 상속받는 Sub로 이루어져 있다. hap()이라는 메서드를 오버라이딩 하고 있다. 이제 이 클래스들을 이용하여 캐스팅을 해보도록 하겠다.

public class Test
{
	public static void main(String[] args)
	{
		Sub ob1 = new Sub();
		System.out.println("ob1.b : " + ob1.b);
	}
}

다음과 같이 Sub 클래스 인스턴스 ob1을 선언하고 그 안에 존재하는 멤버변수 b를 출력하였다. ob1은 자식클래스 이므로 메모리 상에는 상속받은 부모객체 자식(본인)객체가 모두 메모리에 할당될 것이다. 그래서 이를 출력하면 답은 100이 된다.

 

업 캐스팅, 다운 캐스팅

업 캐스팅

다음 코드를 보자.

public class Test
{
	public static void main(String[] args)
	{
		Sub ob1 = new Sub();
		Super ob2 = ob1;
	}
}

Super 참조형 변수 ob2에 ob1을 대입하였다. 과연 이는 문법적으로 올바른 코드일까? 올바른 코드이다. 그 이유는 ob1이 부모객체, 자식객체를 모두 메모리에 가지고 있기 때문이다. ob1이 ob2에 대입될때 암묵적으로 (Super)ob1 형태로 캐스팅 된다. 

 

이렇게 자식객체에서 부모객체형으로 캐스팅하는 것을 업 캐스팅이라고 한다. 

System.out.println("ob2.b : " + ob2.b);             
//--==>> bo2.b : 20                                                             
                                                    
System.out.println("합     : " + ob2.hap());        
// --==>> 합     : 310                         

ob2.write();                      
// --==>> 슈퍼 클래스 write() 메소드...

업캐스팅된 ob2의 멤버변수 b를 출력하면 Super에서 초기화 했던 값 20이 출력된다. 멤버 변수는 객체별로 따로 할당 되기 때문에 이렇게 바뀔 수 있지만 메서드는 다르다.

 

ob2의 클래스 메서드 hap()을 출력하면 310이 나온다. 분명 Super 클래스에 있는 멤버변수들은 20, 10으로 초기화 하였는데, 왜 30이 아닌 310이 나오는 것일까? 이는 hap() 메서드가 오버라이딩 되어 있기 때문이다. 오버라이딩으로 인해 이미 ob1을 생성하는 시점에서 Sub형 hap() 메서드로 덮어쓰기 되었다. 그렇기 때문에 업캐스팅을 하더라도 오버라이딩 된 메서드는 부모 형식의 메서드 기능으로 되돌릴 수 없다.

 

ob2.write() 메서드는 Super 클래스 메서드 이므로 그 함수에 맞게 제대로 출력된다.

 

다운 캐스팅

((Sub)ob2).print();         
// --==>> 서브 클래스 print() 메소드... 

다운 캐스팅은 업 캐스팅과 정 반대로 부모객체에서 자식객체형으로 캐스팅 하는 것이다. 위 코드는 아까 전에 봤던 Super형 ob2 객체를 다운 캐스팅하고 Sub클래스 메서드인 print()를 호출하였다.   

 

하지만 업 캐스팅과 다르게 다운 캐스팅은 주의할 점이 있다. 다음 코드를 보자.

public class Test
{
	public static void main(String[] args)
	{
		Super ob3 = new Super();
		Sub ob4;
	}
}

 ob3는 부모 클래스인 Super의 인스턴스이다. ob4는 자식 클래스를 담을 참조형 변수이다. 이제 ob3, ob4를 이용하여 다음과 같은 코드들을 실행해보자.

System.out.println(ob3.c);                                  
//--==>> 에러 발생(컴파일 에러)                                     

ob4 = ob3;                                                  
//--==>> 에러 발생(컴파일 에러)                                     
                   
ob4 = (Sub)ob3;                                        
//--==>> 에러 발생(런타임 에러)                                                                    

하지만 이 3개의 코드는 모두 에러가 발생한다. 왜 그럴까? 그 이유는 부모 클래스 인스턴스인 ob3 때문이다. ob3 인스턴스는 생성 부분에서 자식 객체가 메모리에 올라가지 않는다.

 

첫번째 코드는 자식 클래스 Sub의 멤버변수인 c에 접근하려고 한다. 하지만 부모 객체는 자식 객체의 멤버변수에 접근하는 것이 불가능하다. 부모 클래스는 자식 클래스가 무엇이 올지 전혀 알 수 없다

 

두번째, 세번째 코드 또한 에러가 발생한다. 부모 객체는 자식 객체에 담을 수 없다.  세번째 코드처럼 명시적인 다운 캐스팅을 하면 문법적으로는 맞지만 실행시 런타임 에러가 발생한다. 이유는 위와 같다. 

 

다운 캐스팅은 업 캐스팅과 다르게 캐스팅이 불가능한 상황이 존재한다. 다음은 이를 정리해놓은 표이다. 이를 유의하며 다운 캐스팅을 사용해야 한다.

 

○ 업캐스팅, 다운 캐스팅이 정상적으로 이루어지는 경우

1. 하위 객체 생성;      // -- check~!!!
2. 상위 = 하위;          // 업 캐스팅. 정상
3. 하위 = 상위;          // 에러 발생. (
4. 하위 = (하위)상위;  // 다운 캐스팅. 정상

○ 다운 캐스팅이 정상적으로 이루어지지 않는 경우

1. 상위 객체 생성;       // -- check~!!!
2. 하위 = 상위;           // 에러 발생.
3. 하위 = (하위)상위;    // 문법상 다운캐스팅. but 런타임 에러 발생.
반응형
Comments