자바의 정석 기초편 ch7-24,25 참조변수의 형변환(2)
car.door,
car.color는 되지만
car.water()는 안된다. < Car 클래스 멤버에 없기 때문에
public class Carto {
public static void main(String[] args) {
Car car = null;
FireEngine fe = new FireEngine();
FireEngine fe2 = null;
fe.water();
car = (Car)fe; // car = (Car)fe;에서 형변환이 생략됨
// car.water();
fe2 = (FireEngine)car; // 자손타입 < 조상타입. 형변환 생략 불가
fe2.water();
}
}
class Car {
String color;
int door;
void drive() { // 운전하는 기능
System.out.println("drive, Brrrr~");
}
void stop() { // 멈추는 기능
System.out.println("stop!!!");
}
}
class FireEngine extends Car { // 소방차
void water() { // 물을 뿌리는 기능
System.out.println("water!!!");
}
}
많이 받는 질문들
Car car = null;
FireEngine fe = null;
둘 다 null이라 객체가 없는데 형변환에는 아무런 문제가 없다.
근데 실행하면 NullPointerException에러가 난다.
왜냐하면 아무객체가 없으니까 에러가 난다.
형변환할 때 중요한 게 실제 인스턴스가 뭔지가 중요하다.
실제 객체의 멤버가 5개니까 5개보다 크면 안 된다.
5개가 기준이 된다.
형변환은 조상, 자손 관계면 무조건 된다.
그렇기 때문에 문법상에는 문제가 없지만, 실제 실행했을 때 문제가 없으려면
참조변수의 멤버를 5개 안으로 줄였다가, 넓혔다가 하는 건 괜찮다.
근데 5개 이상으로 늘리면 안 된다. 5개만 안 넘으면 된다!
형변환이 되냐, 안되냐로 따지는 건 별로 의미가 없다.
참조변수의 타입만 따질 게 아니라, 참조변수들이 가리키는
실제 인스턴스가 뭔지를 확인하고 그 멤버의 개수를 넘어서면 안 된다.
참조변수간의 형변환이 중요한 게 아니라 실제 가리키는 객체가 뭔지가 중요하다.
컴파일러는 형변환 연산자만 써주고, 타입만 맞으면 실제로 객체가 new Car()인지 아닌지 알 수 없다.
그래서 통과가 된다.
Car c = new Car();
FireEngine fe = (FireEngine)c;
fe가 가리키는 객체에 water()를 호출했는데 water()가 없다.
객체가 Car 인스턴스니까
컴파일 에러는 아니고 실행하면 형변환 실행 에러가 나온다.
근데 컴파일러는 속는다. 형변환 타입만 맞으면 컴파일러는 ok
컴파일러가 실제 실행했을 때 어떻게 되는지 다 확인을 못하니까
c와 fe가 조상과 자손의 관계니까 형변환은 가능하지만
실제 인스턴스가 Car인스턴스이기 때문에 멤버 4개를 넘어서면 안 된다.
Car인스턴스의 멤버는 4개니까
FireEngine타입 fe는 멤버가 5개이다.