조상 타입 참조 변수로 자손 타입 객체를 다루는 것이다.
class Tv{
boolean power;
int channel;
void power() { power = !power }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}
class SmartTv extends Tv{
String test;
void caption() { }
}
Tv t=new Tv();
SmartTv s = new SmartTv();
다형성
Tv t=new SmartTv();
다형성은 타입이 불일치하는 것도 허용한다.
일치
불일치
❗️자손 타입의 참조변수로 조상 타입의 객체를 가리킬 수 없다.
SmartTv s=new Tv(); //에러
이와 같은 형태는 불가능하다. s는 기능이 7개인데 Tv의 기능은 5개이기 때문에 안된다. 없는 기능을 누르면 동작이 안되고 없는 기능을 호출했기 때문에 에러가 발생한다.
주소값, 객체가 바뀌는 것이 아닌 사용할 수 있는 멤버의 갯수를 조절하는 것이다.
✅ 참조 변수의 형변환 정리
업캐스팅과 다운캐스팅
- 업캐스팅(upcasting) : 부모 클래스 변수로 자식 클래스 객체를 참조할 수 있다
- 다운캐스팅(downcasting) : 자식 클래스 변수로 부모 클래스 객체를 참조할 수 있다.
class Car{ }
class FireEngine extends Car { }
class Ambulance extends Car { }
FireEngine f = new FireEngine();
Car c = (Car)f;
Ambulance a = (Ambulance)f; //에러
객체 a의 경우 상속관계가 아닌 클래스 간의 형변환을 시도했기 때문에 에러가 발생한다.
class Car{
String color;
int door;
void drive() {
System.out.println("drive");
}
void stop() {
System.out.println("stop");
}
}
class FireEngine extends Car {
void water() {
System.out.println("water");
}
}
public class Test{
public static void main(String args[]) {
Car car = null;
FireEngine fe = new FireEngine();
FireEngine fe2 = null;
fe.water();
car = fe; //형변환 생략
car.water(); //에러
fe2=(FireEngine)car; //조상타입에서 자손타입으로 형변환을 할 때는 생략 불가능
fe2.water();
}
}
car.water()를 했을 때 Car 타입의 참조변수로는 water()를 호출할 수 없기 때문에 에러가 발생한다참조변수의 형변환 가능 여부를 확인할 때 사용한다. 형변환을 하기 전에 반드시 instanceof 연산자를 이용해 확인한 후에 형변환을 해야한다.
if(c instanceof FireEngine) { //형변환이 가능한지 확인
FireEngine fe = (FireEngine)c;
}
c가 가리키는 객체가 FireEngine으로 형변환이 가능한지 확인 후 true가 반환되면 형변환을 진행하면 된다.
✅ 객체 instanceof Object 인 경우 Object는 모든 클래스의 최고 조상이기 때문에 항상 true가 반환된다.
참조형 매개변수는 매서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.
class Product {
int price;
int bonusPoint;
}
class Tv extends Product{ }
class Computer extends Product { }
class Audio extends Product { }
class Buyer {
int money = 1000;
int bonusPoint = 0;
}
//아래 3개의 함수는 오버로딩
void buy(Tv t) {
money -= t.price
bonusPoint += t.bonusPoint;
}
void buy(Computer c) {
money -= c.price;
bonusPoint += c.bonusPoint;
}
void buy(Audio a) {
money -= a.price;
bonusPoint += a.bonusPoint;
}
구매자가 물건을 사기 위해 buy()를 추가하려고 할 때 물건마다 함수를 추가해주어야한다. 많은 메서드를 오버로딩해야하고 코드 중복도 발생한다.
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();
void buy(Product p) {
money -= p.price;
bonusPoint += p.bonusPoint;
}
매개변수를 조상타입인 Product를 사용하게 되면 이 함수하나로 여러 물건 구매가 가능하다. 조상타입의 참조변수로 자손타입의 참조변수를 가리킬 수 있기 때문이다.
조상타입의 배열에 자손들의 객체를 담을 수 있다.
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();
Product[] p = {(new Tv(), new Computer(), new Audio()}
//또는
Product[] p = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();
✅ 다형성의 장점
[출처]
자바의 정석 - https://www.youtube.com/playlist?list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp