메서드 오버라이딩은 어떨때 사용할까?
-> 메서드 오버라이딩은 상위 클래스에서 정의한 메서드가 하위 클래스에서 구현할 내용과 맞지 않을 경우 하위 클래스에서 재정의할 때 사용한다. 오버라이딩을 하려면 반환형, 메서드 이름, 매개변수 개수, 매개변수 자료형이 반드시 같아야 한다. 그렇지 않으면 자바 컴파일러는 재정의한 메서드를 기존 메서드와 다른 메서드로 인식한다.
먼저 Customer 클래스에 calcPrice( ) 메서드가 다음과 같이 존재한다. 해당 메서드는 일반 회원의 가격을 계산하는 메서드이다.
public class Customer {
...
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price;
}
...
}
이번에는 VIPCustomer 클래스에서 10% 할인이 적용된 calcPrice( ) 메서드를 재정의해보자.
public class VIPCustomer extends Customer {
...
@Override
public int calcPrice(int price) {
bonusPoint += price * bonusRatio;
return price - (int)(price * saleRatio);
}
...
}
상위 클래스의 메서드를 재정의할때는 위와 같이 메서드 이름을 직접 써도 되고, 아래 사진과 같이 이클립스 마우스 우측 버튼 클릭에서 [Source -> Override/Implement Methods...]를 클릭하여 재정의를 해줄 수 있다.
코드에서 @Override 애노테이션은 '이 메서드는 재정의된 메서드입니다.' 라고 컴파일러에 명확히 알려주는 역할을 한다.
애노테이션이 존재함으로써 만약 메서드의 선언부가 다르다면 컴파일 오류가 발생하여 프로그래머의 실수를 막아준다.
이렇게 위와 같이 미리 정의되어 있는 애노테이션을 표준 애노테이션이라고 한다.
주로 사용하는 표준 애노테이션은 아래와 같다.
@Override | 재정의된 메서드라는 정보 제공 |
@FunctionalInterface | 함수형 인터페이스라는 정보 제공 |
@Deprecated | 이후 버전에서 사용되지 않을 수 있는 변수, 메서드에 사용됨 |
@SuppressWarnings | 특정 경고가 나타나지 않도록 함 |
** 이 외에도 좀 더 많은 정보를 추가할 수 있는 '메타 애노테이션'을 제공하고 있다.
이제 위에서 구현한 calcPrice( ) 메서드를 통해 두 고객을 생성해서 지불하는 가격을 테스트 해보면 다음과 같다.
public class OverridingTest1 {
public static void main(String[] args) {
Customer customerLee = new Customer(10010, "이순신");
customerLee.bonusPoint = 1000;
Customer customerKim = new VIPCustomer(10020, "김유신", 12345);
customerKim.bonusPoint = 10000;
int price = 10000;
System.out.println(customerLee.getCustomerName() + "님이 지불해야 하는 금액은 " + customerLee.calcPrice(price) + "원입니다.");
System.out.println(customerKim.getCustomerName() + "님이 지불해야 하는 금액은 " + customerKim.calcPrice(price) + "원입니다.");
}
}
// 실행결과
// 이순신 고객은 일반 등급
// 김유신 고객은 VIP 등급
이순신님이 지불해야 하는 금액은 10000원입니다.
김유신님이 지불해야 하는 금액은 9000원입니다.
class Animal {
String name;
void setName(String name) {
this.name = name;
}
}
class Dog extends Animal {
void sleep() {
System.out.println(this.name + " zzz");
}
}
class HouseDog extends Dog {
void sleep() {
System.out.println(this.name + " zzz in house");
}
void sleep(int hour) {
System.out.println(this.name + " zzz in house for " + hour + " hours");
}
}
public class Sample {
public static void main(String[] args) {
HouseDog houseDog = new HouseDog();
houseDog.setName("happy");
houseDog.sleep(); // happy zzz in house 출력
houseDog.sleep(3); // happy zzz in house for 3 hours 출력
}
}
이미 sleep이라는 메서드가 있지만 동일한 이름의 sleep메서드를 또 생성할 수 있다. 단, 메서드의 입력항목이 다를 경우만 가능하다. 새로 만든 sleep메서드는 입력항목으로 hour라는 int 자료형이 추가되었다.
이렇듯 입력항목이 다른 경우 동일한 이름의 메서드를 만들 수 있는데 이를 메서드 오버로딩(method overloading)이라고 부른다.
가상메서드의 동작 원리
프로그램에서 어떤 객체의 변수나 메서드의 참조는 그 타입에 따라 이루어진다.
가상 메서드의 경우는 타입과 상관없이 실제 생성된 인스턴스의 메서드가 호출되는 원리이다.
C++에서는 모든 메서드에 가상 메서드임을 나타내는 virtual 키워드를 써야하지만, 자바는 모든 메서드가 디폴트로 가상메서드로 동작한다.
Customer와 VIPCustomer 클래스에 calcPrice가 모두 존재할 때,다음 코드에서 vc.calcPrice(10000)은 어떤 클래스의 메서드를 호출할까?
Customer vc = new VIPCustomer("10030", "나몰라", 2000);
vc.calcPrice(10000);
정답은 VIPCustomer의 calcPrice( )메서드를 호출하게 된다.
멤버 변수와 메서드는 선언한 클래스형에 따라 호출된다는 전제하에, vc.calcPrice(10000)은 당연히 선언한 클래스인 Customer 클래스의 calcPrcie( ) 메서드를 호출해야 할텐데 출력 결과를 보면 9,000원이 나오는 것으로 보아 VIPCustomer 클래스의 calcPrice( ) 메서드, 즉 재정의된 메서드가 호출되는 것을 확인할 수 있다.
이렇듯 상속에서 상위 클래스와 하위 클래스에 같은 이름의 메서드가 존재할 때 호출되는 메서드는 인스턴스에 따라 결정된다. 다시 말해 선언한 클래스형이 아닌 생성된 인스턴스의 메서드를 호출하는 것이다. 이렇게 인스턴스의 메서드가 호출되는 기술을 '가상 메서드'라고 한다. 가상 메서드가 실행되는 원리를 이해하면 왜 vc.calcPrice(10000)이 Customer 클래스의 메서드가 아닌 생성된 인스턴스, 즉 VIPCustomer의 메서드를 호출하는 지 이해할 수 있다.
'웹 개발 기초 > 자바 문법' 카테고리의 다른 글
다형성 활용, 상속을 사용하는 경우, IS-A 관계, HAS-A 관계 (0) | 2022.12.07 |
---|---|
가상메서드 (1) | 2022.12.06 |
상속에서의 클래스 생성 (0) | 2022.12.05 |
상속과 다형성 (0) | 2022.12.05 |
배열, ArrayList 클래스 (0) | 2022.12.02 |