상위 클래스에서 정의된 메서드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우 하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있고 그것을 오버라이딩 이라고 합니다.
예제의 Customer 클래스의 calPrice()와 VIPCustomer 의 calPrice()구현내용은 할인율과 보너스 포인트 적립내용부분의 구현이 다릅니다. 따라서 VIPCustomer 클래스는 calPrice()메서드를 재정의 할 필요가 있습니다.
오버라이드를 하기 위해 오른쪽 클릭 - Source - Overrride/Implemnet Method...를 클릭하면 변수나 메서드를 선택할 수 있고 calPrice() 메서드를 선택해 생성하면 이전 클래스의 값을 return하는 메서드가 생성됩니다.
메서드를 아래와 같이 수정해 Customer의 carlPrice()와 다른역할을 하는 메서드로 재정의 할 수 있습니다.
//VIPcustomer 클래스
@Override
public int calPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price * salesRatio);
}
@Override는 에너테이션(주석)으로 재정의된 메서드라는 의미로 선언부가 기존의 메서드와 다른 경우 에러가 발생 합니다.
에노테이션은 컴파일러에게 특정한 정보를 제공해주는 역할을 하고 여기서는 재정의된 메서드라는 정보를 제공합니다.
Customer vc = new VIPCustomer();
vc.calPrice(10000);
위의 코드에서 calPrice()메서드는 Customer클래스의 메서드가 호출될 것이라고 생각하기 쉽지만 VIPCustomer클래스의 메서드가 호출됩니다.
Java에서는 항상 인스턴스의 메서드(여기서는 VIPCustomer)가 호출되고 이것을 가상 메서드 기법이라고 합니다.
package inheritance;
public class OverrideTest {
public static void main(String[] args) {
Customer Lee = new Customer();
Lee.setCustomerId(10010);
Lee.setCustomerName("이순신");
Lee.bonusPoint= 1000;
//1번
int priceLee = Lee.calPrice(10000);
System.out.println(Lee.showCustomerInfo()+"지불 금액은 "+priceLee+"원 입니다.");
//이순신님의 등급은 silver이며, 적립된 보너스 포인트는 1100점 입니다. 지불 금액은 10000원 입니다.
VIPCustomer Kim = new VIPCustomer();
Kim.setCustomerId(10020);
Kim.setCustomerName("김유신");
Kim.bonusPoint = 10000;
//2번
int priceKim =Kim.calPrice(10000);
System.out.println(Kim.showCustomerInfo()+"지불 금액은 "+priceKim+"원 입니다.");
//김유신님의 등급은 VIP이며, 적립된 보너스 포인트는 10500점 입니다. 지불 금액은 9000원 입니다.
}
}
OverrideTest 클래스를 만들고 CustomerTest에 내용을 복사해 옵니다.
1번 : Lee가 10000원짜리 물건을 샀다고 가정하고 calPrice메서드를 사용해 priceLee에 price를 대입합니다. 그 후 결과값을 출력문으로 뽑는다면 아래의 결과문 처럼 출력이 됩니다.
2번 : Kim도 같은 물건을 사고 calPrice를 출력해보면 Lee의 것과는 다르게 지불금액이 출력된 것을 확인 할 수있습니다. 이것으로 우리는 priceKim에 calPrice가 Override된것을 알 수 있습니다.
//테스트 클래스
Customer Na = new VIPCustomer();
Na.setCustomerId(10030);
Na.setCustomerName("나몰라");
Na.bonusPoint = 10000;
int priceNa =Na.calPrice(10000);
System.out.println(Na.showCustomerInfo()+"지불 금액은 "+priceNa+"원 입니다.");
//나몰라님의 등급은 VIP이며, 적립된 보너스 포인트는 10500점 입니다. 지불 금액은 9000원 입니다.
위의 코드처럼 상위 메서드인 Customer를 자료형으로 해서 하위 클래스인 VIPCustomer의 인스턴스를 생성한뒤 calPrice메서드를 사용하여 결과값을 보면 Customer클래스의 calPrice가 아닌 VIPCustomer의 calPrice가 사용 된 것을 알 수있습니다.
앞에서 하위 클래스에서 상위 클래스로의 묵시적 형변환이 일어난 경우 상위 클래스의 변수와 메서드만 사용가능한 것과는 다르게 하위 클래스에서 오버라이딩된 메서드가 사용되는 것을 가상메서드라고 합니다.
함수 혹은 메서드는 이름이 그 자체로 주소역할을 하기 때문에 같은 이름을 가진 다른 메서드가 존재할 수 없지만 override를 하는 경우 같은 이름의 다른 주소값을 가진 메서드가 재정의 되기 때문에 같은 이름의 다른기능을 하는 메서드를 가질 수 있습니다. 이처럼 override를 할 수 있는 메서드를 가상 메서드라고 합니다.
위의 그림과 같이 calcPrice는 이름이 같지만 재정의된 다름함수가 존재하고 그 주소값이 다릅니다. 이럴 때 실제적으로 호출되는 calPrice는 자료형(타입)기준이 아닌 생성된 인스턴스를 기준으로 호출이 되는 것을 가상 메서드 기법이라고 합니다.
정리해보면 Customer vd = new VIPCustomer(); 일 때 재정의가 안됬을 경우 Customer의 calPrice가 호출되지만 재정의가 됬을 경우 VIPCustoemr의 calPrice가 호출 됩니다.