일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- string
- Tree
- two pointers
- 파이썬
- dynamic programming
- Counting
- Number Theory
- Binary Search
- Binary Tree
- Matrix
- Stack
- SQL
- Data Structure
- 자바
- Method
- 코테
- java
- 구현
- implement
- bit manipulation
- geometry
- Math
- 코딩테스트
- Class
- array
- sorting
- simulation
- database
- greedy
- hash table
- Today
- Total
코린이의 소소한 공부노트
참조변수의 형변환 본문
참조변수의 형변환은
- 사용할 수 있는 멤버의 개수를 조절하는 것으로,
- 조상-자손 관계의 참조변수는 서로 형변환이 가능하다.
class Parent { // 멤버 3개 }
class Child1 extends Parent { // 멤버 2개 }
class Child2 extends Parent { // 멤버 1개 }
// 메인 내부에서..
Child1 c1 = new Child1();
Parent 클래스를 상속받은 2개의 클래스 Child1, Child2가 있다. 메인에서 Child1 타입의 객체 c1을 생성 후, 어떨 때 참조변수의 형변환이 가능한지 확인해보자.
* 먼저 기억해내야 할 것: 범위가 작은 것 -> 큰 것은 캐스팅이 필요 없지만, 반대 상황에서는 필요하다
int i = 1;
double d = i; // OK
int ii = dd; // error. (int)dd로 바꿔야함
1) 자손->조상으로 형변환(up casting)
Parent p = (Parent)c1; // OK
- 참조변수는 Parent
- c1이 가리키는 객체는 Child1
- 범위: p > c1 -> 조상-자손 관계이므로 형변환이 가능하다.
- 접근 가능한 멤버 수: p 3개 < c1 5개 -> 멤버 수가 감소 -> 형변환을 생략할 수 있다.
- p로 접근할 수 없는 멤버는 Child1에만 있는 멤버 2개다. -> 3개의 멤버는 사용 가능하다.
2) 조상->자손으로 형변환(down casting)
Child1 c2 = (Child1)p; // OK
- 참조변수는 Child1
- p가 가리키는 객체도 Child1
- 범위: c2 < p -> 조상-자손 관계이므로 형변환이 가능하다.
- 접근 가능한 멤버 수: c2 5개 > p 3개 -> 멤버 수가 증가 -> 형변환을 생략할 수 없다.
- c2로 접근할 수 없는 멤버는 없다. -> 5개의 멤버 모두 사용 가능하다.
3) 상속관계가 아닌 클래스로의 형변환
Child2 c3 = (Child2)c1; // error
- 참조변수는 Child2
- c1이 가리키는 객체는 Child1
- 범위: c3 ? c1 -> 조상-자손 관계가 아니므로 형변환이 불가능하다.
[형변환 정리]
1) 기본형의 형변환은 값이 바뀌는 것이다.
(int)3.14 -> 3
(double)3 -> 3.0
2) 참조형의 형변환은 사용(접근) 가능 멤버 개수만 바뀌는 것이다.
- 형변환을 할 때 객체는 바뀌지 않는다.
- 객체가 바뀌지 않기 때문에 주소 값도 바뀌지 않는다.
- 참조변수를 형변환을 하면 형변환당한 참조변수(오른쪽)에 담겨있는 주소가 그대로 복사된다.
- 참조변수의 타입에 따라 객체에 있는 멤버 중 사용 가능한 멤버가 무엇인지 그 개수만 바뀌는 것뿐이다.
글로만 보면 이해가 되지 않을 수 있으니, 위에서 예시로 든 코드와 다른 코드에 그림을 곁들여 설명해보겠다.
class Car { // 차
String color; // 색상
int door; // 문의 개수
void drive() { } // 운전하기
void stop() { } // 멈추기
}
class FireEngine extends Car { // 소방차
void water() { } // 물뿌리기
}
- Car라는 클래스에는 color, door라는 멤버 변수와 drive(), stop()이라는 메서드까지 총 4개의 멤버가 있다.
- Car 클래스를 상속받은 FireEngine이라는 클래스는 water()라는 메서드와 상속받은 멤버까지 총 5개의 멤버가 있다.
이제 메인 메서드에서 형변환 실험을 해보겠다.
Car c = new Car();
FireEngine fe = (FireEngine)c;
fe.water();
- Car 객체 c를 만들었다.
- c를 자손인 FireEngine으로 형변환을 한 후 FireEngine 참조변수에 대입했다.
- fe에서 water() 메서드를 호출했다.
컴파일러는 코드를 확인해봤다.
- Car가 FireEngine의 부모 클래스니까 형변환을 해야 하는 건 맞지!
- fe는 자손의 참조변수니까 water()를 호출할 수 있겠구나. 오케이 통과!
하지만 에러가 발생했다.
FireEngine fe = (FireEngine)c; // runtime error. java.lang.ClassCastException
- 컴파일러는 조상-자손 간의 형변환은 가능하니까 ok 해준 건데 실행시키니까 에러가 발생한 상황
- 인스턴스(Car)의 멤버는 4갠데 참조변수(FireEngine)의 멤버는 5개라서 런타임 에러가 발생
- 여기가 에러가 발생하지 않았다고 하더라도, fe.water()에서 런타임 에러가 발생
왜 에러가 나는지 그림으로도 확인해보자.
Car 객체를 생성하면 멤버가 4개다. 그런데 이 상태에서 형변환을 해서 자손 참조변수에 대입하게 되면, 자손 참조변수 fe는 어리둥절하다. 컴파일러가 통과시켜줬기 때문에 믿고 봤더니만, 난 5개의 멤버를 다룰 수 있는데 실제 객체에는 4개밖에 존재하지 않는다. 그래서 해당 코드에서 에러가 발생하는 것이다. 설사 여기를 통과했다 하더라도, 다음 줄에서 불러올 water()가 없기 때문에 어차피 또 에러가 발생한다.
참조변수의 형변환을 할 때
- 참조변수가 실제로 가리키는 객체가 무엇인지 확인해야 한다.
- 사용 가능한 멤버의 개수가 증가하지 않게 해야 한다.
'Java' 카테고리의 다른 글
다형성의 장점 (0) | 2022.05.04 |
---|---|
instanceof 연산자 (0) | 2022.05.03 |
다형성 (0) | 2022.04.19 |
접근 제어자를 이용한 캡슐화 (0) | 2022.04.18 |
제어자 (0) | 2022.04.16 |