📔 본 포스팅은 자바의 정석(남궁성 저, 3판)을 읽고 정리한 글입니다.
// SmartTv클래스는 Tv클래스의 자손 클래스
SmartTv s = new SmartTv(); // 참조 변수와 인스턴스 타입이 일치
Tv t = new SmartTv(); // 조상 타입 참조변수로 자손 타입 인스턴스 참조
// SmartTv클래스는 Tv클래스의 자손 클래스
Tv t = new SmartTv(); // OK. 허용
SmartTv s = new Tv(); // 에러. 허용 안 됨
결국, 다형성이란 ‘조상 타입으로 선언된 참조변수로는 조상 멤버에만 접근 가능함’을 나타냄
class Car { ... } // 4개의 멤버
class FireEngine extends Car { ... } // 4개의 조상멤버, 1개의 자손 멤버
class Ambulance extends Car { ... }
// ...
FireEngine f = new FireEngine(); // FireEngine인스턴스 생성
Car c = (Car)f; // OK. 조상인 Car타입으로 형변환(생략가능), c는 f가 가리키던 FireEngine인스턴스를 가리킴
FireEngine f2 = (FireEngine)c; // OK. 자손인 FireEngine타입으로 형변환(생략불가)
Ambulance a = (Ambulance)f; // 에러. 상속관계가 아닌 클래스 간의 형변환은 불가능
형변환을 생략 가능한 지 불가능한 지 따질 필요 없이 그냥 전부 형변환을 명시하라!
→ 타입이 안 맞으면 형변환 해주면 그 뿐.
c
와 f
, f2
모두 같은 객체(FireEngine인스턴스)를 가리키지만(같은 주소값을 가지지만),f
, f2
는 FireEngine타입(자손 타입)으로 5개의 멤버 모두 접근 가능하고c
는 Car타입(조상 타입)으로 4개의 멤버(조상 멤버)에만 접근 가능🚩결론
참조변수가 가리키는 실제 객체가 무엇인지를 꼭 확인하고, 그 멤버의 개수를 초과하면 안 된다.
null
이라도 형변환이 가능하다.java.lang.ClassCastException
)public class Ex7_7 {
public static void main(String[] args) {
Car c = new Car();
// 1. 상속관계이기 때문에 어찌됐든 형변환은 가능
// 2. Car의 멤버 개수는 4개인데 FireEngine으로 5개를 사용하려 함
// 3. 실제 객체의 멤버 개수(4개)를 초과했으니 런타임 에러 발생
FireEngine fe = (FireEngine) c; // 형변환 런타임 에러 java.lang.ClassCastException
// FireEngine리모컨에 버튼이 있으니까 water()버튼이 눌리기는 함(컴파일은 됨)
fe.water(); // 컴파일 OK.
}
}
class Car {
String color; // 인스턴스 생성 시 null로 초기화 됨
int door; // 인스턴스 생성 시 0으로 초기화됨
void drive() { }
void stop() { }
}
class FireEngine extends Car { // 소방차
void water() {
System.out.println("water!!!");
}
}
instanceof
로 확인해야함class FireEngine extends Car { ... }
void doWork(Car c) {
if (c instanceof FireEngine) { // 1. c가 FireEngine으로 형변환이 가능한지 확인
FireEngine fe = (FireEngine) c; // 2. 형변환
fe.water();
...
} else if (c instanceof Ambulance){ // 1. 형변환 가능한지 확인
Ambulance a = (Ambulance) c; // 2. 형변환
a.siren();
...
}
class FireEngine extends Car { }
FireEngine fe = new FireEngine();
System.out.println(fe instanceof Object); // true
System.out.println(fe instanceof Car); // true
System.out.println(fe instanceof FireEngine); // true
instanceof
연산 결과는 true이다.🚩 instanceof의 핵심 2가지
- (1) instanceof로 형변환 가능한지 확인하고 (2) 형변환을 해야한다.
- 조상 클래스와 자기 자신에 대한
instanceof
연산 결과는 true이다.
💯 멤버변수들을 주로
private
으로 외부로부터의 직접 접근을 제한하고, 외부에서는 메서드를 통해 간접 접근을 할 수 있게 코드를 작성하라.
→ 애초에 참조변수를 통해 사용되는 인스턴스 변수가 달라지는 일이 없게 코드를 작성한다.
class Product {
int price; // 제품가격
int bonusPoint; // 제품구매 시 제공하는 보너스 점수
Product(int price) { // 생성자
this.price = price;
bonusPoint = (int) (price / 10.0); // 보너스 점수는 제품가격의 10%
}
}
class Tv extends Product {
Tv() { // 조상클래스의 생성자 Product(int price) 호출
super(100); // Tv의 가격을 100만원으로 함
}
public String toString() { return "Tv"; } // Object클래스의 toString()을 오버라이딩
}
class Computer extends Product {
Computer() { super(200); }
public String toString() { return "Computer"; }
}
class Buyer { // 고객
int money = 1000; // 소유 금액
int bonusPoint = 0; // 보너스 점수
void buy(Product p) { // 매개변수의 다형성
if (money < p.price) {
System.out.println("잔액 부족");
return;
}
money -= p.price;
bonusPoint += p.bonusPoint;
System.out.println(p + "을/를 구입하셨습니다."); // p.toString()을 사용한 것과 완전히 같은 연산임
// System.out.println(p.toString() + "을/를 구입하셨습니다.");
}
}
public class Ex21_PolyArgumentTest {
public static void main(String[] args) {
Buyer b = new Buyer();
b.buy(new Tv());
b.buy(new Computer());
System.out.println(b.money);
System.out.println(b.bonusPoint);
}
}
class Buyer2 {
int money = 1000;
int bonusPoint = 0;
Product2[] cart = new Product2[10]; // 자손 타입의 객체를 저장할 수 있는 배열
int i =0;
void buy(Product2 p) {
if(money < p.price) {
System.out.println("잔액 부족");
return;
}
money -= p.price;
bonusPoint += p.bonusPoint;
cart[i++] = p;
System.out.println(p + "을/를 구입했습니다.");
}
void summary() {
int sum = 0;
String itemList ="";
for(int i=0; i<cart.length;i++) {
if(cart[i]==null) break;
sum += cart[i].price;
itemList += cart[i] + ", "; // cart[i].toString()과 같음
}
System.out.println("구입하신 물품 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은 " + itemList + "입니다.");
}
}
class Ex7_9 {
public static void main(String args[]) {
Buyer2 b = new Buyer2();
b.buy(new Tv2());
b.buy(new Computer2());
b.buy(new Audio2());
b.summary();
}
}