자바 가상 메소드 | 자바 입문강좌 28

자바 가상 메소드

자바 가상 메서드에 대해서 먼저 메모리 구조에 눈을 떠야 합니다. 아쉽게도(?) 자바는 프로그래머에게 직접 메모리 액세스 권한을 주지는 않습니다.

이 때문에 제한적인 정보로 파악을 해야 하지만 자바의 기술 문서들이 잘 되있어서 해설을 찾는 것은 어렵지 않습니다.

클래스도 하나의 자료형입니다. 인스턴스를 만들기 전에 클래스를 먼저 로드하는데요. 인스턴스를 두개 만들면 두개의 메모리 영역을 사용하지만 메소드는 어차피 같은 명령어이기 때문에 하나의 메소드는 자동적으로 다수의 인스턴스에 공유가 됩니다.

각종 교재에는 변수의 메모리 위치는 많이 신경쓰는데 의외로 메소드 부분에 대한 설명은 별로 없습니다.

그래서 약간의 부연설명을 하면

프로그램을 크게 두 부분으로 나누면 코드와 데이터가 됩니다. 메소드는 코드이므로 메모리상의 코드세그먼트에 저장됩니다. 같은 클래스의 메소드는 한번만 저장하면 충분하고 인스턴스는 여러개가 될 수 있으니 여러개의 인스턴스는 하나의 메소드(코드 세그먼트)를 가리키게 됩니다.

인스턴스와 메소드를 연결하기 위해서 클래스의 메타 데이터에는 가상 메서드 테이블이 있습니다. 이것으로 인스턴스를 메소드에 연결 시켜주는 것 입니다.

다음의 예제는 인스턴스 별로 다른 메모리 영역을 사용함을 보여줍니다.

package com.kay;

public class Main {

    public static void main(String[] args) {
        BaseA b1 = new BaseA(7,"test-1");
        BaseA b2 = new BaseA(3,"test-2");

        b1.showClass();
        System.out.println("*class ref : " + b1);
        System.out.println();

        System.out.println("--------------");
        b2.showClass();
        System.out.println("*class ref : " + b2);
    }
}

class BaseA{
    int var1;
    String str1;

    public BaseA(int var1, String str1) {
        this.var1 = var1;
        this.str1 = str1;
    }
    public void showClass(){
        System.out.println("var1 = " + var1);
        System.out.println("str1 = " + str1);
    }
}
class SubB extends BaseA{
    public SubB(int var1, String str1) {
        super(var1, str1);
    }
}
var1 = 7
str1 = test-1
*class ref : com.kay.BaseA@4e50df2e

--------------
var1 = 3
str1 = test-2
*class ref : com.kay.BaseA@1d81eb93

인스턴스가 다르면 사용하는 메모리 영역이 다르다는 것은 멤버 변수를 말합니다. 메소드는 메모리 여역이 같을 수밖에 없죠. 메소드에 주소가 있다는 것은 sub 클래스에서 메소드 오버라이딩을 하면 새로운 코드의 주소가 생성됨을 의미합니다.

가상 메소드 예제

package com.kay;

public class Main {

    public static void main(String[] args) {
        BaseA bs1 = new BaseA(222, "BaseA");
        bs1.showClass();
        System.out.println("------------------");

        SubB sb1 = new SubB(333, "SubB");
        sb1.showClass();
        System.out.println("------------------");

        BaseA bs2 = new SubB(777, "casting to BaseA");
        bs2.showClass();
    }
}

class BaseA{
    int var1;
    String str1;

    public BaseA(int var1, String str1) {
        this.var1 = var1;
        this.str1 = str1;
    }
    public void showClass(){
        System.out.println("var1 = " + var1);
        System.out.println("str1 = " + str1);
        System.out.println("<Base method>");
    }
}
class SubB extends BaseA{

    public SubB(int var1, String str1) {
        super(var1, str1);
    }

    @Override
    public void showClass() {
        super.showClass();
        System.out.println("[method override]");
    }
}

var1 = 222
str1 = BaseA
<Base method>
------------------
var1 = 333
str1 = SubB
<Base method>
[method override]
------------------
var1 = 777
str1 = casting to BaseA
<Base method>
[method override]

첫번째 예제의 클래스를 사용했습니다. 이 예제의 결과는 흥미롭습니다. base 참조로 받은 sub 인스턴스에서 오버라이딩한 메소드도 사용할 수 있기 때문입니다.

멤버변수 뿐 아니라 각각의 메소드에 주소가 있다는 것을 기억합니다. base 의 메소드 주소와 sub 메소드의 오버라이딩한 주소 두개가 있는데 첫번째 인스턴스는 base 메소드, 두번째, 세번째 인스턴스는 sub 메소드 오버라이딩으로 갑니다.

base 클래스를 참조하는 변수가 sub 클래스의 오버라이딩한 메소드를 사용한다는 사실입니다.

메소드에 오버라이딩이 되지 않았을 경우엔 원래 메소드를 사용합니다. 이 과정은 컴파일러에 의해서 자동으로 선택됩니다.

요약

조금은 어려울 듯한 자바 가상 메소드에 대해서 알아봤습니다. 지난 학습부터 계속 언급하지만 본인만의 메모리 모델을 머리속에 가지고 있어야 이 과정이 혼란하지 않습니다.

메모리 모델을 머리속에 이미지화 하기 위해서는 자바로는 좀 공부가 어렵고 C나 C++을 배워야 합니다. 혹은 어셈블리어도 도움이 됩니다. 자바에 어느정도 익숙해지면 프로그래밍에 관한 메모리 모델을 배우는 것을 추천합니다.

가상 메소드 테이블 아이디어는 다형성을 하기 위해서 필요한 기초가 되니 이해가 잘 되지 않는다면 다시한 번 돌아보도록 합니다.


외부참고문서

자바 가상 메소드 외

Virtual method table – Wikipedia

Explain what is Virtual table. | Practice | GeeksforGeeks

자바 튜토리얼 메서드 오버라이딩

자바 튜토리얼 함수/메서드(Method)

Leave a Comment