강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

hanikim2057님의 프로필 이미지
hanikim2057

작성한 질문수

(2025) 일주일만에 합격하는 정보처리기사 실기

업캐스팅 (부모 형태, 자식 생성자)

java 자식 클래스 인스턴스에서 부모 클래스의 메서드 호출시 this는 부모를 가리키나요 자식을 가리키나요?

해결된 질문

작성

·

20

0

안녕하세요.

정보처리기사 실기 31강 업캐스팅 강의 10분부터 나오는 '업캐스팅 문제 예시 2번' 예제에서 질문이 있습니다.

 

A b = new B();

이렇게 생성한 인스턴스 b에 대해 b.paint()를 호출하고 내부에서 super.draw()를 호출하고 있는 상황입니다.

 

만약 class A의 draw 메서드 내부에서 draw() 가 아니라 this.draw()를 호출한다고 하면 그때는 B의 메서드가 호출되는지 아니면 A의 메서드가 호출되어 무한루프 도는지 궁금합니다. (부모클래스의 메서드가 실행되고 있을 때 this는 부모를 가리키는지 자식을 가리키는지가 궁금합니다.)

답변 2

0

주말코딩님의 프로필 이미지
주말코딩
지식공유자

안녕하세요,

무한루프가 돌지 않고 자식 draw를 실행합니다.

 

A b = new B();로 생성했을 때, 실제 객체는 B 타입입니다.

A 클래스 내의 메서드가 실행 중이어도 B의 인스턴스를 가리킵니다.

부모 내에서 this.draw()를 해도 재정의한 B의 인스턴스를 실행합니다.

 

public class MainClass {
    public static void main(String[] args) {
        A a = new A();
        A b = new B();
        
        b.paint();
        b.draw();
    }
}

class A {
    public A() {
        System.out.println("Constructor of A");
    }
    
    public void paint() {
        System.out.print("A");
        draw();
    }
    
    public void draw() {
        System.out.print("B");
        this.draw();
    }
}

class B extends A {
    public B() {
        System.out.println("Constructor of B");
    }
    
    public void paint() {
        super.draw();
        System.out.print("C");
        this.draw();
    }
    
    public void draw() {
        System.out.print("D");
    }
}

 

출력값

Constructor of A

Constructor of A

Constructor of B

BDCDD

 


 

(+답변 추가) 만약에 무한루프를 돌게 하고 싶다면 방법이 아예 없는 것은 아닙니다.

 

부모의 메서드에 private으로 한정해버리면 오버라이딩을 할 수 없어서 무한루프를 일으킬 수 있습니다. 이 때도 this가 있든 없든 자기 자신을 실행하기 때문에 무한루프입니다.

 

static(하이딩)이나 final(상수화)을 통해서도 만들 수 있는데.. 그렇게까지는 시험에 나오지 않을 것 같습니다.

주말코딩님의 프로필 이미지
주말코딩
지식공유자

무한루프 예제

 

다른 예제로서 계속 B가 출력되는 형태 소스코드 알려드립니다.

public class MainClass {
    public static void main(String[] args) {
        A b = new B();
        b.paint();  // "A" 출력 후 "BBBBBB..." 무한루프!
    }
}

class A {
    public void paint() {
        System.out.print("A");
        draw();
    }
    
    private void draw() {  // private이 핵심!
        System.out.print("B");
        draw();  // 자기 자신을 계속 호출 → 무한루프!
    }
}

class B extends A {
    // private 메서드는 오버라이딩이 안되므로
    // 이것은 A의 draw()와 완전히 별개의 메서드입니다
    public void draw() {
        System.out.print("D");
    }
}

 

출력값: ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB....(무한루프)

hanikim2057님의 프로필 이미지
hanikim2057
질문자

늦은시간에 답변 주셔서 감사합니다. 질문했던 내용은 이해되었는데 추가로 말씀주신 부분이 이해가 어려워 추가 질문드립니다.

 

부모의 draw 메서드를 private으로 한정하면 오버라이딩할 수 없다면, 무한루프 도는 과정은 다음과 같은 원리인 게 맞을까요?

A b = new B()로 생성한 b에서 draw 메서드가 private이면 오버라이딩할 수 없어 무조건 상속받은 메서드를 사용해야 하고, 즉 this(인스턴스 b)의 draw 메서드는 A에서 상속받은 draw이기 때문에 draw 내부에서 draw 호출하여 무한루프를 돌게 된다.

 

+추가로 예시로 적어주신 코드에서 b.print() 메서드 내부에서 b는 new B()로 만든 인스턴스인데 draw()를 했을 때 B의 public draw가 아니라 A의 private draw가 호출되는 이유는 혹시 private과 public 메서드에 우선순위가 있어서일까요?

주말코딩님의 프로필 이미지
주말코딩
지식공유자

제가 드린 무한루프 예제에서 메인함수에서 애초에 draw()를 부른 적이 없습니다.

메인함수에서는 b.paint()를 호출합니다.

 

자식은 paint를 재정의하지 않았으니 public으로 상속 받아온 그대로를 사용합니다.

그런데 부모의 paint에서는 draw가 있네요. private은 같은 클래스 내에서는 접근 가능합니다.

(이 개념은 싱글턴 패턴에서도 배웁니다.)

 

그래서 부모의 draw를 부른 것입니다.

 

저 상태에서 메인함수에서 draw를 부르면 애초에 상속을 못했기 때문에 오류가 발생합니다.

public class MainClass {
    public static void main(String[] args) {
        A b = new B();
        b.draw(); // 이렇게 바꾼다면?
    }
}

메인함수만 위 코드로 바꾼다면,

 

 error: draw() has private access in A
        b.draw();  // "A" ?? ? "BBBBBB..." ????!
         ^
1 error
ERROR!
error: compilation failed

이렇게 오류 발생.

 

어쨌든, 일반적인 경우에서는 대체로 자식이 오버라이딩한 메서드 상태는

부모에서 무한루프를 일으키는 경우는 없다고 생각하셔도 됩니다.

hanikim2057님의 프로필 이미지
hanikim2057
질문자

아 제가 질문을 헷갈리게 작성했습니다.

추가로 예시 주신 코드의 main 함수가 아니라 main에서 호출한 b.print() 메서드 내부에서 draw() 호출할 때, B에 draw라는 public 메서드가 있고 A에 private draw라는 메서드가 있는 상황으로 보여서 print 내부에서 draw를 호출할 때 B의 public draw가 아니라 A의 private draw가 호출되는 이유가 궁금했습니다.

 

무한루프를 돌게 하고 싶었던 건 아니고 this가 어떤 객체를 가리키는지가 궁금했던 거라, 답변 감사드립니다.

0

안녕하세요, 인프런 AI 인턴입니다. hanikim2057님.

Java에서 상속과 관련된 this 키워드의 동작은 객체지향 프로그래밍에서 중요한 개념입니다. 질문하신 상황과 관련된 개념을 간단히 설명드리겠습니다.

A b = new B();로 인스턴스를 생성하면, b는 데이터 타입 A의 참조를 가지지만, 실제로 참조하고 있는 객체는 B의 인스턴스입니다. 이와 같은 업캐스팅 상황에서 메서드 호출이 이루어질 때, Java는 가상 메서드 호출(Virtual Method Invocation)이라는 메커니즘을 사용하여 객체의 실제 타입에 따라 메서드를 선택하여 실행합니다.

  • super.draw()this.draw()의 차이:
    • super.draw(): 부모 클래스인 A에 정의된 draw() 메서드를 명시적으로 호출합니다. 이 경우에는 A의 메서드가 호출됩니다.
    • this.draw(): 현재 객체의 실제 타입에 따라 draw() 메서드를 호출합니다. bB의 인스턴스이므로, 오버라이드된 Bdraw() 메서드가 호출됩니다.

따라서, 부모 클래스인 A에서 this.draw()를 호출하면, 실제 참조되는 객체 Bdraw() 메서드가 실행됩니다. 이로 인해 B에서 오버라이드된 메서드가 호출됩니다. this는 항상 현재 인스턴스, 여기서는 B를 가리키므로, A로의 무한루프가 발생하지 않습니다.

업캐스팅과 관련된 개념은 다음과 같은 기존 질문과 답변에서 깊이 있게 다뤄진 바 있습니다. 참고하시기 바랍니다:

  1. 자바 업캐스팅 개념 이해하기

  2. 상속과 this/super 키워드 활용법

위 링크들은 질문하신 예제와 유사한 내용으로 업캐스팅 및 this, super 키워드의 차이를 명확하게 설명하고 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

hanikim2057님의 프로필 이미지
hanikim2057

작성한 질문수

질문하기