오버라이딩(overriding)
@Override
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price * salesRatio);
}
Customer vc = new VIPCustomer();
그렇다면 vc.calPrice()를 호출했을 때 어떤 메서드가 호출될까?
결과는 인스턴스의 메서드인 override된 메서드가 호출된다. 앞서 우리가 아는 개념은 메모리에 잡히는 건 VIPCustomer객체이지만 타입이 Customer이기 때문에 vc가 접근가능한 것은 Customer객체의 변수와 메서드들이었다.
그러나 자바에서는 항상 인스턴스의 메서드가 호출(가상메서드의 원리)되고 자바의 모든 메서드는 가상 메서드(virtual method)이다.
위에서 말했듯이 메서드는 항상 인스턴스의 메서드가 호출된다. Customer vc = new VIPCustomer(); 이 경우에도 프로그램이 로드될 때 메서드 영역에 Customer,VIPCustomer클래스의 명령어 set이 모두 위치하게 된다(vc의 타입이 Customer일지라도 인스턴스는 VIPCustomer이기 때문에) 따라서 메서드 영역에 calcPrice,(override)calcPrice가 있는데 override된 경우는 override된 메서드의 주소를 가리켜 실행되는 것이 가상 메서드의 원리이다.
package ch03.polymorphism;
import java.util.ArrayList;
public class CustomerTest {
public static void main(String[] args) {
ArrayList<Customer> customerArrayList = new ArrayList<>();
Customer customerT = new Customer(1,"A");
Customer customerJ = new Customer(2,"B");
Customer customerE = new GoldCustomer(3,"C");
Customer customerW = new GoldCustomer(4,"D");
Customer customerQ = new VIPCustomer(5,"E");
customerArrayList.add(customerT);
customerArrayList.add(customerJ);
customerArrayList.add(customerE);
customerArrayList.add(customerW);
customerArrayList.add(customerQ);
for (Customer c : customerArrayList){
System.out.println(c.showCustomerInfo());
}
int price = 10000;
for (Customer c : customerArrayList){
int cost = c.calcPrice(price);
System.out.println(c.getCustomerName()+"'s cost : "+cost);
System.out.println(c.getCustomerName()+"'s bonusPoint : "+c.bonusPoint);
}
}
}
실행 결과와 같이 같은 메서드지만 결과가 모두 다르게 나옴
Customer vc = new VIPCustomer(); //묵시적
VIPCustomer vCustomer = (VIPCustomer)vc; //명시적
그러나 다운캐스팅하는 방식은 비추천, 웬만하면 override하는 방식으로 해결하는 것이 좋음
public void testDownCasting(ArrayList<Animal> list){
for(int i=0 ; i<list.size() ; i++){
Animal animal = list.get(i);
//instanceof로 해당인스턴스가 맞는지 check
if(animal instanceof Human){
Human human = (Human)animal;
human.readBook();
}
else if(animal instanceof Tiger){
Tiger tiger = (Tiger)animal;
tiger.hunting();
}
else if(animal instanceof Eagle){
Eagle eagle = (Eagle)animal;
eagle.fly();
}
else{
System.out.println("unsupported");
}
}