상속과 다형성 - 2. 객체의 타입변환

Ⅱ. 객체의 타입변환

1. 객체의 타입변환 (업캐스팅과 다운캐스팅)

 - 상속관계에 있는 경우 객체도 타입변환이 가능

 - 업캐스팅은 항상 가능 : 생략시 컴파일러에 의해 자동캐스팅

 - 다운캐스팅은 때에 따라서 가능/불가능 : 가능한 경우에만 수동으로 직접 캐스팅 필요

// Example
package sample;

class A {}
class B extends A{}
class C extends B{}
class D extends B{}

public class Test {
	public static void main(String[] args) {		
		// 1. 업캐스팅 (자동변환): 생략시 컴파일러가 자동 추가
		// ※ new 를 무엇으로 했느냐가 중요
		A ac = (A)new C(); // C->A 업캐스팅 (자동변환) 자동변환은 앞에 (A)가 없어도 됨
		B bc = (B)new C(); // C->B 업캐스팅 (자동변환)
		
		B bb = new B();
		A a = (A)bb; //B->A 업캐스팅 (자동변환)
		
		// 2-1. 다운캐스팅 (수동변환) : 캐스팅이 불가능한 경우 (실행시 예외발생)
		A aa = new A();	// 실질적으로 A인 A객체
		// B b = (B)aa; //A->B 다운캐스팅 (수동변환)
		// B는 A의 자식이라 불가능 (B가 A보다 자원이 더 많으므로 메모리에 무리)
		// C c = (C)aa; //A->C 다운캐스팅 (수동변환)
		
		// 2-2. 다운캐스팅 (수동변환) : 캐스팅이 가능한 경우 
		A ab = new B();	// 실질적으로 B인 A객체		
		B b = (B)ab; //A->B 다운캐스팅 (수동변환)
		// C c = (C)ab; //A->C 다운캐스팅 (수동변환) : 불가능
		
		B bd = new D();
		D d = (D)bd; //B->D 다운캐스팅 (수동변환)
		
		A ad = new D();
		B b1 = (B)ad; //A->B 다운캐스팅 (수동변환)
		D d1 = (D)ad; //A->D 다운캐스팅 (수동변환)				
	}
}

2. 메모리로 이해하는 다운캐스팅

 - 다운 캐스팅이 가능하기 위해서는 Heap 메모리 내에 해당 객체가 있어야 함

 

3. 선언 타입에 따른 차이점

 - 선언한 타입의 멤버만 사용 가능

//Example
package sample;

class A {
	int m = 3;
	void abc() {
		System.out.println("A");
	}
}

class B extends A {
	int n = 4;
	void bcd() {
		System.out.println("B");
	}
}

public class Main {
	public static void main(String[] args) {
		B b = new B();
		System.out.println(b.m);	// 3
		System.out.println(b.n);	// 4
		b.abc();			// A
		b.bcd();			// B
		
		A a = new B();
		System.out.println(a.m);	// 3
		// System.out.println(a.n);	// 불가능
		a.abc(); 			// A
		// a.bcd();			// 불가능
	}
}

 

4. 다운캐스팅 가능 여부 확인

 - instanceof : 캐스팅의 가능여부를 확인 (true / false)

// Example
package sample;

class A{}
class B extends A{}

public class Main {
	public static void main(String[] args) {		
		//#1. instanceof
		A aa = new A();
		A ab = new B();
		
		System.out.println(aa instanceof A); 	// true
		System.out.println(ab instanceof A); 	// true
		
		System.out.println(aa instanceof B); 	// false
		System.out.println(ab instanceof B); 	// true
		
		if(aa instanceof B) {
			B b = (B)aa;
			System.out.println("aa를 B로 캐스팅하였습니다.");
		} else {
			System.out.println("aa는 B 타입으로 캐스팅이 불가!!!");
		}			
		if(ab instanceof B) {
			B b = (B)ab;
			System.out.println("ab를 B로 캐스팅하였습니다.");
		} else {
			System.out.println("ab는 B 타입으로 캐스팅이 불가!!!");
		}		
		if ("안녕" instanceof String) {
			System.out.println("\"안녕\"은 String 클래스입니다");
		}
	}
}