Java 컴파일타임 바인딩

코딩Java
읽는데 7분 소요
처음 쓰여진 날: 2026-05-19
마지막 수정일: 2026-05-19
조회수:

요약

Java에서 오버로드 선택이 컴파일 시점에 선언 타입을 기준으로 결정되는 원리를 알아봅니다. 26년1회 실기에 처음 출제된 신규 패턴으로, 오버로딩과 오버라이딩이 한 코드에 섞였을 때 어떤 메서드 호출로 고정되는지 단계별로 추적합니다.

컴파일타임 바인딩 핵심 정리

이 표에서 자주 나오는 용어를 미리 짚어 둡니다. 선언 타입은 변수를 선언할 때 지정한 타입으로, A a = new B();에서 a의 선언 타입은 A입니다. 오버로드 선택이란 같은 이름의 메서드가 여러 개 있을 때 어느 메서드를 호출할지 결정하는 과정입니다. 같은 이름이라도 매개변수 타입이 다르면 다른 메서드로 취급합니다 (예: f(Object)f(String)).

항목내용
결정 시점오버로드 선택은 컴파일 시점에 고정
결정 기준호출 지점의 선언 타입 + 인자 타입
런타임 동작이미 결정된 메서드의 실제 구현(오버라이딩 결과)을 실행
혼동 포인트자식에 더 좁은 타입(예: Object 대신 String)을 받는 메서드가 있어도, 호출이 부모 시야에서 일어나면 선택되지 않음

컴파일 시점 vs 런타임 시점 심화

Java 코드가 처리되는 과정은 두 단계로 나뉩니다. 컴파일 시점1은 소스 코드를 .class 파일로 변환하는 단계이고, 런타임2은 변환된 .class 파일을 JVM이 실제로 실행하는 단계입니다. 두 단계의 개념을 자세히 살펴보려면 컴파일과 런타임의 차이 페이지를 참고하세요.

오버로드 선택은 컴파일 시점에 결정됩니다. 같은 이름의 메서드가 여러 개일 때 어떤 것을 고를지는, 호출 코드를 컴파일하는 순간의 변수 선언 타입3인자 타입만으로 정해집니다. 컴파일러는 소스 코드만 보고 타입 정보를 분석하기 때문에, 런타임에 실제로 어떤 객체가 들어올지는 알 수 없습니다. 그래서 실제 객체 타입은 오버로드 선택에 반영되지 않습니다. 런타임에는 이미 결정된 메서드 호출이 실행됩니다.


오버로딩 vs 오버라이딩 — 결정 시점 차이 심화

개념결정 시점기준
오버로딩컴파일타임 (정적 바인딩4)호출 지점에서 본 선언 타입 + 인자 타입
오버라이딩런타임 (동적 바인딩5)실제 생성된 객체의 타입

두 개념이 한 코드에 섞여 있으면 두 단계로 순서대로 결정됩니다. 예를 들어 A a = new B(); a.f("hello"); 코드가 있을 때, 먼저 컴파일 시점에 "어느 메서드를 호출하는가"가 a의 선언 타입 A를 기준으로 f(Object) 호출로 고정되고, 그다음 런타임에 "그 메서드의 실제 구현을 어느 클래스가 가지고 있는가"가 실제 객체 타입 B를 보고 결정됩니다.

"컴파일 시점에 정보가 고정되고 런타임에는 그 결과만 실행된다"는 메커니즘은 제네릭과 타입 소거 페이지의 타입 소거 동작과 닮아 있습니다. 둘 다 컴파일 단계에서 결정된 정보로 동작이 묶이고, 런타임에는 그 결과만 실행됩니다.


선언 타입 기준으로 오버로드가 결정됩니다 심화

오버로드 후보를 찾는 규칙에는 통합된 메타 규칙이 하나 있습니다. "오버로드 후보는 호출 코드가 쓰인 위치에서 컴파일러가 볼 수 있는 메서드 집합(시야)에서 결정된다." 변수를 통해 호출할 때는 그 변수의 선언 타입이 시야를 결정하고, 메서드 본문 안에서 this.f() 형태로 호출할 때는 그 본문이 속한 클래스가 시야를 결정합니다. 즉 "시야" = "호출 코드가 쓰인 위치에서 컴파일러가 그 시점에 볼 수 있는 메서드 집합"입니다.

오버로드 후보6는 이 시야를 기준으로 찾습니다.

java
코드 하이라이팅 중...

B의 두 메서드가 오버라이딩인지 오버로드인지를 A의 메서드와 비교하면 다음과 같습니다.

B의 메서드A의 메서드와 비교관계
f(Object x)f(Object) — 이름과 매개변수 타입 동일오버라이딩 (런타임 교체)
f(String x)f(Object)와 매개변수 타입 다름오버로드 (B에만 존재)

A a = new B();는 업캐스팅입니다. 업캐스팅이란 부모 타입 변수에 자식 객체를 담는 것으로, BA를 상속하므로 A 타입 변수에 담을 수 있습니다. 단, 컴파일러는 aA 타입으로만 인식합니다. 업캐스팅 개념은 오버라이딩 페이지에서 자세히 다룹니다.

  • a의 선언 타입은 A입니다.
  • 오버로드 후보는 선언 타입의 시야에서 결정됩니다. a의 선언 타입이 A이므로 컴파일러는 A에 선언된 메서드만 봅니다. 따라서 A에는 f(Object) 하나만 있으므로, 컴파일러는 a.f("hello")f(Object) 호출로 고정합니다. 런타임에 실제 객체가 B임을 알더라도 이미 오버로드 선택은 끝났으므로 B의 f(String)은 후보조차 되지 않습니다.
  • 런타임에는 실제 객체가 B이고 f(Object)가 B에서 오버라이딩되었으므로 B의 f(Object)가 실행되어 "2"를 돌려줍니다.

StringObject의 하위 타입이므로 f(String)이 더 구체적으로 맞지만, A의 시야에서는 f(String) 자체가 선택지로 존재하지 않기 때문에 호출되지 않습니다.

선언 타입 A vs 실제 객체 B로 결과가 달라지는 예시:

java
코드 하이라이팅 중...
A의 시야에는 f(Object) 하나만 보이지만 B의 시야에는 f(Object)와 f(String)이 모두 보인다
컴파일러는 선언 타입 A의 시야에서 후보를 찾아 f(Object)로 고정하고, 런타임에 실제 객체 B가 오버라이딩한 f(Object)를 실행하여 "2"를 반환합니다.

정보처리기사 실기 기출 문제


Footnotes

  1. 컴파일 시점(compile time): Java 소스 파일(.java)을 javac가 바이트코드(.class)로 변환하는 단계. 이 단계에서 타입 검사, 오버로드 선택이 이루어집니다.

  2. 런타임(runtime): JVM이 .class 파일을 실제로 실행하는 단계. 오버라이딩 선택, 실제 객체 생성 등이 이 단계에서 이루어집니다.

  3. 변수 선언 타입: 변수를 선언할 때 지정한 타입. A a = new B();에서 a의 선언 타입은 A입니다. 실제 객체 타입(B)과 다를 수 있습니다.

  4. 정적 바인딩(static binding): 컴파일 시점에 어떤 메서드를 호출할지 확정하는 것. 오버로딩이 대표적입니다.

  5. 동적 바인딩(dynamic binding): 런타임에 실제 객체 타입을 보고 어떤 메서드를 호출할지 결정하는 것. 오버라이딩이 대표적입니다.

  6. 후보(candidate): 컴파일러가 오버로드를 선택할 때 고려하는 메서드 목록. 시야(= 호출 코드가 쓰인 위치에서 컴파일러가 볼 수 있는 메서드 집합)에 속한 메서드들만 후보가 됩니다. 예를 들어 A a = new B();에서 a.f()를 호출하면 시야는 선언 타입 A이므로, A에 선언된 메서드만 후보입니다.


Java 컴파일타임 바인딩 | 정처기 감자