본문 바로가기

Java/문법

10-2장 객체의 타입 변환

1. 객체의 업캐스팅과 다운캐스팅

 

 1) 업캐스팅 

  -  자식 클래스에서 부모 클래스 쪽으로 변환

  - 컴파일러가 자동으로 넣어줌

 

 2) 다운캐스팅 

  - 부모클래스에서 자식 클래스 쪽으로 변환

  - 직접 명시적으로 넣어줘야함

  - 잘못된 다운캐스팅을 수행하면 ClassCastException 예외 발생

 

 3) 객체 타입 변환의 예

 

  3)-1  사람 <- 학생 

업캐스팅 학생사람이다. 항상 o
다운캐스팅 사람학생이다. 학생인 사람이라면 o
학생이 아닌 사람이라면 x
사람 human1 = new 사람(); //학생과 학생이 아닌 사람이 모두 포함된 사람 객체 
사람 human2 = new 학생(); //학생인 사람 객체

 - 첫번째 객체  human1

  - 사람() 생성자를 이용해 객체를 생성한 후 사람 자료형에 대입

  - 사람들이 공통된 속성과 기능들만 포함 

  - 학생으로의 다운캐스팅 불가능 

 

 - 두번째 객체 human2

  - 학생() 생성자를 이용해 객체를 생성한 후 사람 자료형에 대입 

  - 객체 내부에는 사람의 공통된 특성뿐 아니라 학생의 속성과 기능포함 

  - 학생으로의 다운 캐스팅 가능 

 

 3)-2 

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

 - 업캐스팅 

B b1 = new B();
A a1 = (A) b1; //컴파일러가 자동으로 추가 

C c2 = new C();
B b2 = (B) c2; //컴파일러가 자동으로 추가 
A a2 = (A) c2; //컴파일러가 자동으로 추가

- 다운캐스팅

A a1 = new A(); //A() 생성자로 만든 A타입
B b1 = (B) a1; //예외 발생

A a2 = new B(); //B() 생성자로 만든 A타입
B b2 = (B) a2; //(o)
C c2 = (C) a2; //예외 발생

   - A() 생성자로 만든 A타입은 B타입으로 다운캐스팅 불가 -> ClassCastException 예외 발생 

   - B() 생성자로 만든 A타입은 B타입으로의 다운캐스팅 가능 -> 객체 자체가 B타입으로 만들어져 있음 

   - B() 생성자로 만든 A타입을 C타입으로 다운캐스팅 불가

   - 캐스팅 가능 여부는 무슨 타입으로 선언돼 있는지는 중요하지 않고 어떤 생성자로 생성됐는지가 중요 

 

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

 

 A<-B<-C 상속관계 

 

1) A a = new B(); 

 -  실제 객체는 B() 생성자로 만듬 

 -  A 객쳬 (부모 클래스)가 먼저 메모리에 만들어지고 ,이후 B 객체 (자식 클래스)가 생성 

 -  이 객체를 A타입의 참조 변수로 가리키고 있음 

 - 실제 참조 변수는 힙 메모리의 B 객체 안에 있는 A객체를 가리키게 됨 

 

 2) B b = (B) a; 

  - A 타입의 a를 B 차입으로 캐스팅해 B타입으로 저장 

  - a는 A 객체를 가리켰지만, (B) a는 B 객체를 가리켜야 함 

  - 힙 메모리에 이미 B 객체 있으니까 문제 없음

 

 3) C c = (C) a;

 - 다운캐스팅 불가능 

 - 참조 변수 c는 C타입을 가리켜야 하는데, 힙 메모리에는 C타입 객체가 만들어진적이 없음

  - 클래스의 업캐스팅 및 다운캐스팅

package Inheritance;

//클래스의 상속관계
class A{} 
class B extends A{}
class C extends B{}
class D extends B{}

public class Typecasting_1 {
	public static void main(String [] args) {
		//업캐스팅(자동 변환) : 캐스팅 구문을 생략했을 때 컴파일러가 자동으로 추가 
		A ac = (A) new C(); // C->A 업캐스팅
		B bc = (B) new C(); // C->B 업캐스팅
		
		B bb = new B();
		A a= (A)bb; //B->A 업캐스팅
		
		//다운캐스팅(수동 변환) :캐스팅할 수 없을 때 (실행할때 예외 발생)
		A aa = new A();
	  //B b = (B) aa;  A-> B 다운캐스팅 불가능
	  //C c = (C) aa;  A ->C 다운캐스팅 불가능
		
		A ab = new B(); 
		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 다운캐스팅
	}
}

 

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

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

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

- B의 객체를 B 타입으로 선언

B b = new B();
System.out.println(b.m); //(o)
System.out.println(b.n); //(o)
b.abc(); //(o)
b.bcd(); //(o)

 - 힙 메모리에 A객체를 감싸고 있는 B객체가 만들어짐 

 - 참조 변수가 B타입으로 선언돼 있으므로 참조 변수 b는 B객체를 가리키게 되고, 이떄 참조변수를 이용해 2개의 필드와 2개의 메서드를 모두 사용 가능 

 

- B의 객체를 A타입으로 선언

A a = new B();
System.out.println(a.m); //(o)
System.out.println(a.n); //(x)
a.abc(); //(o)
a.bcd(); //(x)

 - 힙 메모리에 생성된 객체의 모양은 동일

 - 참조 변수가 A타입으로 선언돼 있으므로 실제로 힙 메모리에 B 객체가 있더라도 참조 변수 a는 A 객체만을 가리킴

  ( m과 abc()만 사용가능)

 

4. 캐스팅 가능 여부를 확인하는 instanceof 키워드 

 

 - 캐스팅 여부를 알려면 실제 객체를 어떤 생성자로 만들었는지와 클래스 사이의 상속관계를 알아야 함

 - 타입 : 참조 변수가 표현될 수 있는 모든 다형적 타입 

참조 변수 instanceof 타입 //true : 캐스팅 가능 false : 캐스팅 불가능

- A<-B<-C 상속 구조 

C c = new C();
System.out.println(c instanceof A); //true
System.out.println(c instanceof B); //true
System.out.println(c instanceof C); //true

 - A<-B 상속 구조에서 instanceof의 결괏값에 따른 캐스팅 구문의 예 

A ab = new B();
if(ab instanceof B) { //true
 	B b = (B) ab; //캐스팅 구문 실행
}

A aa = new A();
if(aa instanceof B) { //false
	B b = (B) aa; //캐스팅 구문은 실행되지 않음
 }