다형성은 크게 2가지로 나눌 수 있다.
예시)
class Friend {
String name;
public void friendInfo() {
System.out.println("나는 당신의 친구입니다.");
}
}
class GirlFriend extends Friend {
int height;
public void friendInfo() {
System.out.println("나는 당신의 여자친구입니다.");
}
}
public class FriendTest {
public static void main(String[] args) {
// 객체 타입과 참조변수 타입의 일치
Friend friend = new Friend();
// (가능⭕) 상위 클래스의 타입으로 하위 클래스의 객체를 참조
Friend girlfriend1 = new GirlFriend();
// (불가능❌) 하위 클래스의 타입으로 상위 클래스의 객체를 참조
GirlFriend girlfriend2 = new Friend();
friend.friendInfo();
girlfriend.friendInfo(); // 오버라이딩된 메소드가 호출
// GirlFriend 클래스의 height 변수에 접근 불가
girlfriend.height = 160;
}
}
// 출력값
나는 당신의 친구입니다.
나는 당신의 여자친구입니다.
✅
상위 클래스
타입의 참조 변수로하위 클래스
의 객체를 참조 가능
❌하위 클래스
타입의 참조 변수로상위 클래스
의 객체를 참조할 수 없다!
✅ 참조 변수가 사용할 수 있는 멤버 = 상위 클래스의 멤버
Friend 타입으로 GirlFriend 인스턴스를 참조하면, Friend 클래스의 멤버만 사용할 수 있다.
GirlFriend 클래스의 멤버는 사용하지 못하므로, 오히려 사용할 수 있는 멤버는 줄어들게 된다.
❓ 왜 하위 클래스의 타입으로 상위 클래스 객체를 참조하는 것은 불가능할까?
💁♀️ 객체(상위 클래스)의 멤버 개수보다, 참조 변수(하위 클래스)의 멤버 개수가 많기 때문이다.
(객체의 멤버 수 > 참조 변수의 멤버 수): 실제 사용할 수 있는 기능을 사용하지 않는 것이기 때문에 문제가 없음
(객체의 멤버 수 < 참조 변수의 멤버 수): 사용할 수 있는 기능이 구현되지 않은 것이므로 문제가 발생한다.
public class VehicleTest {
public static void main(String[] args) {
Car car = new Car();
// 업 캐스팅
Vehicle vehicle = car;
// 다운 캐스팅(괄호 생략 불가능)
Car car2 = (Car) vehicle;
// 상속관계가 아니므로 타입 변환 불가 -> 에러발생
MotorBike motorBike = (MotorBike) car;
}
}
class Vehicle {}
class Car extends Vehicle {}
참조_변수 instanceof 타입
public class InstanceOfExample {
public static void main(String[] args) {
Animal animal = new Animal();
System.out.println(animal instanceof Object); //true
System.out.println(animal instanceof Animal); //true
System.out.println(animal instanceof Bat); //false
Animal cat = new Cat();
System.out.println(cat instanceof Object); //true
System.out.println(cat instanceof Animal); //true
System.out.println(cat instanceof Cat); //true
System.out.println(cat instanceof Bat); //false
}
}
class Animal {};
class Bat extends Animal{};
class Cat extends Animal{};
분명 "하위 클래스
타입의 참조 변수로 상위 클래스
의 객체를 참조할 수 없다"라고 배웠는데 어떻게 다운 캐스팅
이 가능할까?
다운 캐스팅은 단순히 하위 클래스
타입의 참조 변수로 상위 클래스
의 객체를 참조하는 것이 아니다.
다운 캐스팅은 업 캐스팅
이 선행된 후에, 다시 원래 타입으로 돌아가는 것을 말한다.(원상 복구)
따라서 그냥 하위 클래스가 상위 클래스 객체를 참조하는 것은 불가능하지만, 업 캐스팅 후에 다운 캐스팅을 하는 것은 가능하다.
그리고 그때 instanceof 연산자가 사용된다.
public class Main {
public static void main(String[] args) {
// (업 캐스팅) 상위 클래스의 타입으로 하위 클래스 타입의 객체를 참조
Friend girlfriend = new GirlFriend();
// (다운 캐스팅 X) 하위 클래스의 타입으로 상위 클래스 타입의 객체를 참조
// Exception 발생!
GirlFriend friend1 = (GirlFriend) friend;
}
}
코드는 비슷한 형태이지만, 다운 캐스팅의 경우에는 exception이나 오류가 발생하지 않는다.
public class Main {
public static void main(String[] args) {
// 상위 클래스의 타입으로 하위 클래스 타입의 객체를 참조(= 업 캐스팅)
Friend girlfriend = new GirlFriend();
// 다운 캐스팅
GirlFriend friend = (GirlFriend) girlfriend;
}
}