뭐지?

[Java] p는 Child 객체인데, 왜 p.x는 Child의 변수가 아닐까?

호기심 많은 솔이 2025. 4. 16. 21:19

오늘 아래의 연습 문제를 풀다가 이해가 되지 않는 부분이 생겨서 그 부분에 대해 공부한 후 이 글을 쓰게 되었다.

 

 

Q) 다음의 코드를 실행한 결과를 적으시오.

 

내가 했던 생각을 적어보자면, Parent p = new Child();에서 p가 가리키는 객체는 Parent타입이지만 Child의 객체이다. 따라서 p.x는 Child 객체의 x값이 출력돼야 하고, p.method()를 호출하면 Child 클래스의 메서드 내용이 출력돼야 한다.

 

따라서 이 코드를 실행한 결과는

p.x = 200

child Method

c.x = 200

child Method

이다.

 

 

 

하지만 실제 출력 결과는 달랐다.

 

실제 출력 결과

 

출력의 첫 줄에서 p.x = 200이 아니라 p.x = 100이 출력되었다.

 

이 출력 결과를 보고 이해가 가지 않아서 내가 뭘 모르고 있었는지, 올바른 개념은 무엇인지 궁금해져서 검색을 통해 찾아보고 GPT한테도 물어보았다.

 

 

여기서 얻은 결과를 정리해 보자면,

 

p.method()는 내가 생각했던 대로 실제 객체가 Child이므로 child Method가 출력되는데, 그 이유는 메서드는 기본적으로 동적 바인딩(Dynamic Binding) 대상이므로 런타임 시점에 어떤 메서드를 호출할지가 결정된다. 즉, 참조 변수가 가리키고 있는 메모리 주소를 통해 실행되는 것이다.

 

이와 달리, p.x에서 x는 변수(필드)인데, 변수(필드)는 항상 정적 바인딩(Static Binding) 대상이다. 즉, 컴파일 시점에 어떤 멤버를 사용할지가 결정되므로 Parent 타입을 기준으로 결정되는 것이다. 따라서 p.x의 값은 Child 객체의 x값인 200이 아니라, Parent 객체의 x값인 100이 출력된 것이다.

 

 

Q) 여기서 컴파일 시점에 결정되면 왜 Parent타입 기준으로 결정되는 거고, 런타임 시점에 결정되면 왜 Child타입 기준으로 결정되는 거지?

-> (일반) 메서드는 자식 클래스에서 오버라이딩이 가능하기 때문에, 자바는 method()를 실행할 때까지 기다렸다가 실제 객체가 누구인지 보고 결정한다. 이것이 동적 바인딩이고, 동적 바인딩은 다형성의 핵심 개념이다.

 

하지만, 변수는 바뀌지 않기 때문에 타입만 보고 결정★ 해도 된다. 이것이 정적 바인딩이다.

 

 

여기서 컴파일 시점, 런타임 시점이라는 용어의 의미와 정적 바인딩, 동적 바인딩이라는 용어의 의미를 간단히 설명해 보자면,

 

컴파일 시점이란?

- 자바 코드를 .java로 작성하고 컴파일러가 .class 파일로 바꾸는 시점.

- 오타, 타입 오류 등을 잡아내는 시점.

--> 예를 들어, 인텔리제이에서 우리가 코드를 작성 중인 시점. 실행시키기 전에 느낌표나 빨간 줄이 뜨는 그 시점으로 이해하면 된다.

 

런타임 시점이란?

- 코드를 실제로 실행한 다음, JVM이 돌아가는 시점.

- 예외가 발생하거나 실제 객체가 메서드를 실행하는 시점.

- main() 실행 후 코드들이 동작하는 그 순간 정도로 이해하면 된다.

 

바인딩이란?

-> 어떤 메서드나 변수에 연결되는 것. 쉽게 말해, 어떤 메서드나 변수를 쓸 건지 결정하는 것.

 

정적 바인딩이란?

- 바인딩이 컴파일 시점에 일어나는 것. 컴파일러가 "이 변수는 얘 거다!" 하고 고정해버림

- 적용 대상 : 필드(변수), static 메서드, final 메서드, private 메서드.

 

동적 바인딩이란?

- 바인딩이 런타임 시점에 일어나는 것. 즉, 코드 실행 중에 "이 메서드는 실제로 어떤 객체의 것을 호출해야 하지?"를 판단함.

- 적용 대상 : 인스턴스 메서드(일반 메서드)