자바의 클래스는 멤버 변수와 메서드로 이루어져 있다. 클래스를 생성해서 인스턴스가 만들어지면 멤버 변수는 힙 메모리에 위치한다.
그렇다면 메서드는 어디에 위치할까?
변수가 사용하는 메모리와 메서드가 사용하는 메모리는 다르다.
변수는 인스턴스가 생성될 때마다 새로 생성된다. 하지만 메서드는 실행해야 할 명령 집합이기 때문에 인스턴스가 달라도 같은 로직을 수행한다. 즉 같은 객체의 인스턴스를 여러 개 생성한다고 해서 메서드도 여러 개 생성되지 않는다.
예를 들면 다음 코드의 실행 결과와 같다.
public class TestA {
int num;
void aaa( ) {
System.out.println("aaa( ) 출력");
}
public static void main(String[] args) {
TestA a1 = new TestA( );
a1.aaa();
TestA a2 = new TestA( );
a2.aaa();
}
}
// 실행결과
aaa( ) 출력
aaa( ) 출력
위 코드가 실행되는 메모리의 상태는 다음과 같다.
main( ) 함수가 실행되면 지역 변수는 스택 메모리에 위치한다. 그리고 각 참조 변수 a1과 a2가 가리키는 인스턴스는 힙 메모리에 생성된다. 그리고 메서드의 명령 집합은 메서드 영역(코드 영역)에 위치한다.
그래서 메서드를 호출하면 메서드 영역의 주소를 참조하여 명령이 실행되기 때문에 인스턴스가 달라도 동일한 메서드가 호출되는 것이다.
가상메서드의 원리
일반적으로 프로그램에서 메서드를 호출한다는 것은 그 메서드의 명령 집합이 있는 메모리 위치를 참조해서 명령을 실행하는 것이다.
그런데 가상 메서드의 경우에는 '가상 메서드 테이블'이 만들어진다. 가상 메서드 테이블은 각 메서드 이름과 실제 메모리 주소가 짝을 이루고 있다.
어떤 메서드가 호출되면 이 테이블에서 주소 값을 찾아서 해당 메서드의 명령을 수행한다.
(메서드 호출 -> 가상메서드 테이블 참조 -> 해당 메서드의 주소값을 참조해서 명령 수행)
다음 그림을 보면 이해가 쉽다.
그림에서 보듯 calcPrice( ) 메서드는 두 클래스에서 서로 다른 메서드 주소를 가지고 있다.
이렇게 재정의된 메서드는 실제 인스턴스에 해당하는 메서드가 호출된다.
showCustomer( )와 같이 재정의되지 않은 메서드인 경우는 메서드 주소가 같으며 상위 클래스의 메서드가 호출된다.
다음 예제는 Customer 클래스, VIPCustomer 클래스, VIPCustomer 클래스로 인스턴스를 생성하여 Customer 클래스 형으로 형 변환한 경우 각각 얼마를 지불해야 하는지 출력하는 예제이다.
public class OverridingTest3 {
public static void main(String[] args) {
int price = 10000;
Customer customerLee = new Customer(10010, "이순신");
System.out.println(customerLee.getCustomerName() + " 님이 지불해야 하는 금액은 " + customerLee.calcPrice(price) + "원 입니다.");
VIPCustomer customerKim = new VIPCustomer(10020, "김유신", 12345);
System.out.println(customerKim.getCustomerName() + " 님이 지불해야 하는 금액은 " + customerKim.calcPrice(price) + "원 입니다.");
Customer vc = new VIPCustomer(10030, "나몰라", 2000);
System.out.println(vc.getCustomerName() + " 님이 지불해야 하는 금액은 " + vc.calcPrice(10000) + "원 입니다.");
}
}
// 출력 결과
이순신 님이 지불해야 하는 금액은 10000원 입니다.
김유신 님이 지불해야 하는 금액은 9000원 입니다.
나몰라 님이 지불해야 하는 금액은 9000원 입니다.
위 결과와 같이 Customer 클래스와 VIPCustomer 클래스로 인스턴스를 생성했을 때는 정상적으로 남은 금액이 출력되고,
VIPCustomer로 생성하고 Customer형으로 변환한 vc는 원래 Customer형 메서드가 호출되는게 맞지만 가상 메서드 방식에 의해 VIPCustomer 인스턴스의 메서드가 호출되어 할인 가격인 9000원이 출력된다.
정리하자면 상위 클래스(Customer)에서 선언한 calcPrice( ) 메서드가 있고 이를 하위 클래스(VIPCustomer)에서 재정의한 상태에서 하위 클래스 인스턴스(vc)가 상위 클래스로 형 변환이 되었다. 이때 vc.calcPrice( )가 호출되면, vc 변수를 선언할 때 사용한 자료형(Customer)의 메서드가 호출되는 것이 아니라 생성된 인스턴스(VIPCustomer)의 메서드가 호출된다.
이를 가상메서드라고 하며, 자바의 모든 메서드는 가상 메서드이다.
'웹 개발 기초 > 자바 문법' 카테고리의 다른 글
다운캐스팅, instanceof (0) | 2022.12.08 |
---|---|
다형성 활용, 상속을 사용하는 경우, IS-A 관계, HAS-A 관계 (0) | 2022.12.07 |
메서드 오버라이딩, 메서드 오버로딩, 가상 메서드의 원리 (0) | 2022.12.05 |
상속에서의 클래스 생성 (0) | 2022.12.05 |
상속과 다형성 (0) | 2022.12.05 |