참조변수의 형변환
기본형 변수와 같이, 참조변수 또한 형변환이 가능함.
조건: 서로 상속관계에 있는 클래스 사이에서만 가능하다.
- 자손타입 참조변수 → 조상타입 참조변수
- 조상타입 참조변수 → 자손타입 참조변수
class Car { }
class FireEngine extends Car { }
class Ambulance extends Car { }
위와 같이 클래스가 존재하는 경우,
Car ↔ FireEngine
Car ↔ Ambulance
FireEngine (불가능) Ambulance
class Car { }
class FireEngine extends Car { }
class Ambulance extends Car { }
FireEngine f = new FireEngine(); // 인스턴스 = FireEngine
Car c = (Car)f; // FireEngine 인스턴스를 Car로 형변환. 조상으로 형변환이기에 생략 가능
FireEngine f2 = (FireEngine)c; // 본래 인스턴스가 FireEngine인 Car의 참조변수 c를 다시 FireEngine으로 형변환. 자손으로의 형변환이기에 생략 불가
Ambulance a = (Ambulance)f; // FrieEngine의 참조변수 f를 Ambulance로 형변환 불가능. 에러
// f의 값(객체 주소)을 c에 저장
// 이 때, c와 f가 타입이 다르므로, 멤버 개수가 줄어드는 f는 자동 형변환(생략 가능)
Car c = f;
// 조상타입 c의 값(객체주소)를 자손타입 참조변수에 저장하려면.. 형변환 필요.
// 조상 타입을 자손으로 형변환하기에 생략 불가능.
f = (FireEngine) c;
참조변수의 형변환은 뭐 객체 이런게 바뀌지 않음 절대.
사용할 수 있는 "멤버"의 개수만 바뀐다.
여기서 내가 계속 헷갈리는데.. 책에 다음과 같이 적혀있다.
" 서로 상속관계에 있는 타입간의 형변환은 양방향으로 자유롭게 수행될 수 있으나, 참조변수가 가리키는 인스턴스의 자손타입으로 형변환은 허용되지 않는다. 그래서 참조변수가 가리키는 인스턴스의 타입이 무엇인지 먼저 확인하는 것이 중요하다 "
[내가 헷갈린 것]
- 조상에서 자손 타입으로의 형변환 시 타입 생략 불가
- 그런데 위에서는 참조변수가 가리키는 인스턴스의 자손 타입으로 형변환이 안된대! 뭐야?!?
[해결]
- 자손인 FireEngine으로 new 키워드 이용하여 객체 생성 (f 참조변수)
- 인스턴스가 FireEngine이기에, 조상인 Car로 형변환 가능(이때 생략 가능, 참조변수 c)
- Car로 형변환 하더라도.. 기능이 사라진 것이 아니라 기능을 사용할 리모컨 버튼이 하나 없어진 것
- 참조변수 c를 다시 f2로 형변환한다. 이 때, 자손 타입으로 형변환하는 것이기에 생략 불가능. FireEngine의 기능 다시 사용 가능해진다
▶ 결국 사용 가능한 멤버 개수 조절용일 뿐.. 헷갈리지 말자. 포인트는 인스턴스가 무엇인가? (new 위치 파악)
class Car {
String color;
int door;
void drive() {
System.out.println("drive, Brrrrr...");
}
void stop() {
System.out.println("STOP!!");
}
}
class FireEngine extends Car{
void water() {
System.out.println("warter!!!!");
}
}
public class Ex7_7 {
public static void main(String[] args) {
Car car = null;
FireEngine fe = new FireEngine(); // 인스턴스는 FireEngine임을 기억하
FireEngine fe2 = null;
fe.water();
car = fe; // 생략 가능. 조상으로의 형변환
//car.water(); 사용 불가능. car 리모컨은 water() 기능 버튼이 없다
fe2 = (FireEngine)car; // 인스턴스가 FireEngine이기에 충분히 가능하다
fe.water();
}
}
instanceof 연산자
- 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof 연산자를 사용함.
- 주로 조건문에 사용.
- (참조변수) instanceof (타입, 클래스명)
- boolean값 반횐
void doWork(Car c) {
if(c instanceof FireEngine) {
FireEngine fe = (FireEngine)c;
fe.water();
....
}
}
위 함수는 Car 타입의 참조변수 c를 매개변수로 받는다.
즉, 매개변수로 Car 클래스 또는 그 자손 클래스의 인스턴스를 넘겨받는 것(다형성)
메서드 내에서는 정확히 어떤 타입의 인스턴스인지 알 수 없음.
이 때 instanceof 연산자로 c가 어떤 인스턴스를 가리키는지 확인한 후 적절히 형변환 후 작업한다.
#조상 타입의 참조변수로 자손 타입의 인스턴스를 참조할 수 있기에.. 참조변수 타입과 인스턴스 타입이 항상 일치하지는 않음을 기억하자.
#조상타입의 참조변수로는 실제 인스턴스 멤버들을 모두 사용할 수 없기 때문에... 실제 인스턴스와 같은 타입의 참조변수로 형변환 해야 인스턴스의 모든 멤버를 사용할 수 있음.
어떤 타입에 대한 instanceof 연산의 결과가 true라는 것은.. 검사한 타입으로 형변환이 가능하다는 의미이다.
// instanceof의 결과.. 조상들에 대해서도 참이 나온다는 사실을 기억하셈.
FireEngine fe = new FireEngine();
fe instanceof Object //ture
fe instanceof Car //ture
fe instanceof FireEngine //ture
- fe가 참조하는 인스턴스의 멤버 중 적어도 하나는 Object의 멤버이다.
(걍 모든 클래스의 root조상이 Object임)
▶ fe의 자식타입으로는 형변환 안되지만, 조상은 가능.^^
'프로그래밍 > java' 카테고리의 다른 글
[JAVA] 추상 클래스와 추상 메서드 (abstract) (0) | 2022.08.31 |
---|---|
[JAVA] 매개변수의 다형성, 객체 배열과 벡터 (0) | 2022.08.31 |
[JAVA] 다형성(polymorphism) (0) | 2022.08.28 |
[JAVA] 패키지와 import, 제어자, 겟터와 셋터 (0) | 2022.08.28 |
[JAVA] 오버라이딩(overriding)과 참조변수 super, super() 생성자 (0) | 2022.08.27 |