본문 바로가기
Language/Java

[JAVA] 가상 메서드(Virtual Method)의 심층 이해와 다형성의 핵심 메커니즘

by Papa Martino V 2026. 1. 17.
728x90

Virtual Method
Virtual Method

 

자바(Java)를 깊이 있게 공부하다 보면 '다형성(Polymorphism)'이라는 거대한 장벽에 마주하게 됩니다. 그리고 그 장벽을 넘기 위한 핵심 열쇠가 바로 가상 메서드(Virtual Method)입니다. 단순히 "상속받은 메서드가 실행된다"는 수준을 넘어, JVM 내부에서 어떤 일이 벌어지는지 이해하는 것이 진정한 자바 전문가로 거듭나는 길입니다. 본 포스팅에서는 가상 메서드의 정의부터 JVM의 메서드 테이블(Method Table) 동작 원리, 그리고 실무에서 흔히 저지르는 실수까지 상세히 다루어 보겠습니다.

 

--- ## 1. 가상 메서드(Virtual Method)란 무엇인가?

자바에서 가상 메서드는 실행 시점(Runtime)에 객체의 실제 타입에 따라 호출될 메서드가 결정되는 메서드를 의미합니다. 자바는 기본적으로 모든 비-정적(non-static) 메서드를 가상 메서드로 취급합니다.

C++과 같은 언어에서는 virtual 키워드를 명시해야 하지만, 자바는 객체 지향의 유연성을 극대화하기 위해 이를 기본 동작으로 설계했습니다. 덕분에 개발자는 상속 관계에서 부모 타입의 참조 변수를 사용하더라도, 자식 클래스에서 오버라이딩(Overriding)된 메서드를 안전하게 호출할 수 있습니다.

 

### 동적 바인딩(Dynamic Binding)의 마법

가상 메서드의 핵심은 동적 바인딩에 있습니다. 컴파일러는 컴파일 시점에 어떤 메서드가 호출될지 알지 못합니다. 대신 실행 중에 JVM이 인스턴스의 실제 메모리 주소를 확인하여 적절한 구현체를 찾아냅니다.

 

--- ## 2. 가상 메서드의 동작 원리: 가상 메서드 테이블(VMT)

JVM은 효율적인 메서드 호출을 위해 가상 메서드 테이블(Virtual Method Table, VMT)을 관리합니다. 각 클래스가 로드될 때, 해당 클래스의 메서드 주소값들을 담은 테이블이 메모리에 생성됩니다.

  • 상속 관계: 자식 클래스가 부모의 메서드를 오버라이딩하지 않았다면, VMT는 부모의 메서드 주소를 가리킵니다.
  • 오버라이딩: 자식 클래스가 메서드를 재정의했다면, VMT의 해당 슬롯은 자식 클래스의 새로운 메서드 주소로 업데이트됩니다.

이 메커니즘 덕분에 실행 시간의 오버헤드를 최소화하면서도 강력한 다형성을 구현할 수 있습니다.

 

--- ## 3. 정적 메서드 vs 가상 메서드 비교

모든 메서드가 가상 메서드인 것은 아닙니다. static, private, final 키워드가 붙은 메서드는 가상 메서드에서 제외됩니다. 이들은 정적 바인딩(Static Binding)을 따르기 때문입니다.

구분 가상 메서드 (Virtual Method) 비가상 메서드 (Non-virtual Method)
결정 시점 실행 시점 (Runtime) 컴파일 시점 (Compile-time)
바인딩 방식 동적 바인딩 (Dynamic Binding) 정적 바인딩 (Static Binding)
해당 메서드 일반 인스턴스 메서드 static, private, final 메서드
주요 특징 오버라이딩 가능, 다형성 구현 오버라이딩 불가, 속도 빠름
참조 주소 객체 인스턴스에 따라 다름 클래스 타입에 따라 결정됨

 

--- ## 4. 실전 예제로 보는 가상 메서드

아래 코드를 통해 실제 가상 메서드가 어떻게 동작하는지 확인해 보겠습니다.


class Animal {
    void sound() {
        System.out.println("동물이 소리를 냅니다.");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("멍멍!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog(); // 업캐스팅
        myDog.sound(); // 결과: "멍멍!"
    }
}

 

위 코드에서 myDog의 타입은 Animal이지만, 실제 메모리에 생성된 인스턴스는 Dog입니다. 자바의 가상 메서드 구조 덕분에 myDog.sound()를 호출하면 Animal의 메서드가 아닌, 실제 객체인 Dog의 오버라이딩된 메서드가 호출됩니다.

 

--- ## 5. 주의사항: 필드(Field)는 가상인가?

여기서 많은 초급 개발자들이 혼동하는 점이 있습니다. "메서드는 가상이지만, 필드(변수)는 가상이 아니다"라는 점입니다. 멤버 변수는 참조 변수의 타입에 따라 결정되므로, 다형성을 적용할 때 반드시 메서드를 통해 접근(Getter/Setter)하는 것이 설계상 유리합니다.

 

--- ## 6. 결론: 왜 가상 메서드를 알아야 하는가?

가상 메서드는 자바 객체 지향 프로그래밍의 근간입니다. 이를 이해해야만 인터페이스 기반 설계, 추상 클래스 활용, 그리고 디자인 패턴(특히 전략 패턴이나 템플릿 메서드 패턴)을 정확하게 구사할 수 있습니다. 시스템의 유연성을 높이고 유지보수가 용이한 코드를 작성하고 싶다면, 가상 메서드의 원리를 항상 염두에 두어야 합니다.

 

--- ### 출처 및 참고 문헌

  1. Gosling, J., Joy, B., Steele, G., & Bracha, G. (2014). The Java Language Specification, Java SE 8 Edition. Addison-Wesley.
  2. Lindholm, T., Yellin, F., Bak, G., & Chung, A. (2014). The Java Virtual Machine Specification, Java SE 8 Edition. Oracle.
  3. Oracle Java Documentation: "Polymorphism and Method Overriding".
  4. Bruce Eckel (2006). Thinking in Java (4th Edition). Prentice Hall.
728x90