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; //캐스팅 구문은 실행되지 않음
}
'Java > 문법' 카테고리의 다른 글
10-4장 인스턴스 필드와 정적 멤버의 중복 (0) | 2023.06.01 |
---|---|
10-3장 메서드 오버라이딩 (0) | 2023.05.04 |
10-1장 클래스 상속의 개념과 문법적 특징 (0) | 2023.05.04 |
9-2장 static 제어자 (0) | 2023.04.30 |
9-1장 접근 지정자 (0) | 2023.04.30 |