다음 코드의 실행 결과가 어떻게 될까요?
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.call();
}
static class Parent {
public void call() {
this.helloWorld(); // 사실 this가 없어도 결과는 동일합니다
}
public void helloWorld() {
System.out.println("===================");
System.out.println("부모입니다");
System.out.println("===================");
}
}
static class Child extends Parent {
@Override
public void helloWorld() {
System.out.println("===================");
System.out.println("자식입니다");
System.out.println("===================");
}
}
}
결과는 다음과 같습니다.

this는 말 그대로 '자기 자신'를 의미하고, call메서드의 자기 자신은 Parent니깐 "부모입니다"가 출력되겠구나! 라고 생각했지만 아니었습니다. 지금부터 그 이유에 대해 살펴보겠습니다.
this가 단순히
현재 객체를 의미한다고 알고 계셨던 분들이라면 이 글이 도움이 될 수도 있습니다.
Java에서 실행할 메서드를 선택하는 과정은 다음과 같습니다.
이는 코드를 실행해보기 전 컴파일 시점에는 어떤 메서드가 실행될지 알 수 없고 런타임에 비로소 알 수 있다는 의미입니다.
위 예제에서 만약 Child객체에 call메서드가 존재했다면 Child의 call메서드가 실행됐을 겁니다. 하지만 실제로 Child객체는 call메서드가 존재하지 않았고, 부모인 Parent의 call메서드가 실행됐습니다. 이러한 내용은 런타임에 결정되기 때문에 동적 메서드 탐색이라 부릅니다.
객체가 메시지를 수신하면 컴파일러는 self참조라는 임시 변수를 자동으로 생성한 후 메시지를 수신한 객체를 가리키도록 설정합니다.
동적 메서드 탐색은 self참조가 가리키는 객체의 클래스에서 시작해 상속 계층의 역방향으로 이뤄지며, 메서드 탐색이 종료되는 순간 self참조는 자동으로 소멸됩니다.
그리고 우리가 궁금해하던 this는 이 self참조가 가리키는 객체를 의미합니다.

따라서 처음에 보여드린 코드는 다음과 같이 동작합니다. (중간에 있어야 할 Child인스턴스에 대한 그림은 생략했습니다.)

1. Child에 call메시지를 전송하면 Child의 인스턴스를 가리키는 self참조가 설정되고, Child클래스에서부터 메서드 탐색이 시작됩니다.
2. Child클래스에는 call메시지를 처리할 수 있는 메서드가 존재하지 않아 부모 클래스인 Parent에서 메서드 탐색을 계속합니다. Parent클래스의 call메서드를 발견하고 이를 실행하게 됩니다.
3. Parent클래스의 call메서드를 실행하는 중 this를 마주합니다. 이때 this는 self참조가 가리키는 객체를 의미합니다.
4. 따라서 this.helloWorld()의 의미는 self참조가 가리키는 객체에서부터 시작해 helloWorld라는 메서드를 탐색하라는 의미입니다. 메시지 탐색은 Parent클래스에서 벗어나 self참조가 가리키는 Child에서부터 다시 시작됩니다.
5. Child에서 helloWorld메서드를 발견하고 이를 실행한 후 동적 메서드 탐색을 종료합니다.
this는 현재 클래스를 의미하는 게 아니라 처음 메시지를 받은 객체(self참조가 가리키는 객체)를 의미한다
this에 대한 oracle 공식문서 설명은 아래와 같습니다.
