4books
10
2018-12-07 19:16:19
3
109

Java class 상속에 대한 질문입니다.


public class parents{


public class Parents{ //조상 클래스입니다.
	public void output(){
		System.out.println("조상클래스입니다.");
	}
}

public class Child extends Parents{ // parents에게 상속받는 자손 클래스 Child입니다.
    public void output(){
		System.out.println("자손클래스입니다.");
    }
}

public class Test {
	public static void main(String[] args) {
                Parents t1 = new Child(); 
                //여기서 Child 클래스 객체 생성하고 조상 클래스 타입의 참조변수로
                //자손 클래스의 인스턴스를 참조할 수 있도록 생성하였습니다.
t1.output(); } }

그런데 이렇게 되면 method를 조상의 것을 받아 출력되기 때문에 

"조상클래스입니다"라고 출력되어야 하지 않나요?

그런데 실제로는 "자손클래스입니다"가 출력됩니다.

같은 method명을 가지고 있어도 속성에 클래스타입을 조상클래스로 하면

조상클래스의 method를 사용한다고 알고 있는데 잘못 알고 있는건가요?

많은 분들 도움을 바랍니다 ㅠㅠ

0
0
  • 답변 3

  • 엔카나
    277
    2018-12-07 19:26:57

    컴파일러는 컴파일 과정에서 참조변수가 실제 어떤 클래스의 인스턴스를 참조하는지 기억하지 않습니다.

    즉, Parent t1 = new Child(); 를 컴파일할때에는 Child 클래스가 Parent 클래스를 상속했는가 여부를 확인 후 상속했다면 정상적으로 컴파일하고 그 다음문장으로 넘어갑니다.

    중요한건 "참조변수 t1 이 Child 인스턴스를 참조하구나" 라고 생각하지 않는다는거죠.

    그냥 "오케이, Child 는 Parent 를 상속하니 문제없음 통과" 라고 생각합니다.


    그리고나서 t1.output(); 을 컴파일할때에는 위에서 말씀드렸다 싶이 t1 이 실제 참조하는 인스턴스를 기억하지 않고있기 때문에, 참조변수 t1 의 자료형(클래스)에 output 메소드가 존재하는지를 검사합니다.

    Parent형 참조변수 t1은 Parent 인스턴스 또는 이를 상속하는 클래스의 인스턴스를 참조할 수 있습니다.

    컴파일러 관점에서는 t1 이 어떤 인스턴스를 참조하든간에 t1 의 자료형인 Parent 클래스의 모든 메소드는 반드시 존재한다는 보장이 있기 때문에 Parent 클래스에서 호출할 메소드의 존재유무를 검사하는거죠.


    하지만, 실제 코드들을 실행시키는 JVM은 다릅니다.

    JVM 은 참조변수가 실제 참조하는 인스턴스에서 해당 메소드를 찾고 실행합니다.

    따라서, Compile Time 에서는 Parent 의 메소드가 사용되는거고 RunTime 에서는 Child 의 메소드가 사용되는겁니다.

    3
  • 엔카나
    277
    2018-12-07 19:28:24

    조금 객체지향론적인 이야기를 하자면,

    부모 클래스 타입의 참조변수로 자식 클래스의 객체를 참조하는 행위가 가능한 이유를 먼저 파악해야합니다.

    사람은 어떠한 물건,물체 (통틀어 객체라고도 표현합니다.)를 눈으로 보면 이에 대한 정보를 머릿속에 특정 개념으로 저장한다고 합니다.
    그럼 지금 당장 눈앞에 보이는 삼성 LED 모니터를 질문자님은 어떠한 개념으로 머릿속에 저장하실건가요?
    "물건" 이라는 개념으로 머릿속에 저장할 수도 있고, "전자제품" 이라는 개념으로 머릿속에 저장할수도 있고 더 작게는 "모니터" 라는 개념으로 머릿속에 저장할수도 있습니다.
    분명 그 모니터는 삼성사에서 제작한 LED 모니터이고 제품번호도 존재하는데, 우리는 이 모니터를 떠올리고 부를 때 "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 이라고 하지 않고 "모니터" 라고 합니다.
    왜냐하면 "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 는 "모니터" 가 가져야할 모든 특성을 지니고 있기 때문이죠.
    달리 말하면 "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 를 "선풍기" 라는 개념으로 머릿속에 저장하진 않습니다. 왜냐하면, "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 는 선풍기의 모든 특성을 지니지 않기 때문이죠.


    이것과 마찬가지로, 자식 클래스의 객체는 부모 클래스 객체의 모든 특성을 지닙니다.
    (여기서 말하는 특성은 필드와 메소드 모두를 말합니다.)
    그렇기 때문에 자식 객체를 부모 객체라는 개념으로 저장할 수 있고, 또 그렇게 부를수도 있는거죠.
    이것이 부모 클래스의 참조변수로 자식 객체를 참조할 수 있는 이유와 일맥상통합니다.
    이건 객체지향론에서 설명하는 내용입니다.
    자바는 객체지향 프로그래밍 언어이기 때문에 이 내용을 적용했구요.

    그럼, 왜 부모 클래스의 참조변수로는 부모 클래스의 맴버에만 접근이 가능할까요?
    "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 에는 게이밍 모드라는 특별한 기능이 있다고 가정해보겠습니다.
    그리고 컴퓨터에 대해 지식이 많지 않은, 컴퓨터를 단순히 인터넷 서핑용으로만 사용하는 분에게
    이 "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 을 모니터라고 말하고 선물했을 때 선물을 받으신분은 이 "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 를 단순히 "모니터" 라는 개념으로 머릿속에 저장할겁니다.
    "모니터" 는 전원을 on/off 하는 기능과 명암 조절과 같은 단순한 디스플레이 조절 기능이 들어있다는 사실은 누구나 알고있죠.
    그래서 선물을 받으신 분은 전원을 on/off 하고 디스플레이 조절은 가능합니다.
    하지만, 게이밍 모드 on/off 를 해보라고 하면 못하겠죠.
    이 분의 머릿속에 저장된 "삼성전자 제품의 LED 모니터 제품번호 LE-3333" 는 그저 단순한 "모니터" 이니까요.

    마찬가지로, 부모 클래스의 참조변수로 자식 객체를 참조하면 이 순간부터 컴파일러는 자식 객체를 부모 객체라는 개념으로 바라봅니다.
    따라서, 부모 클래스의 참조변수로 접근 가능한 맴버는 부모 클래스에 정의된 맴버로 제한이 되죠.


    자바 언어 관점에서 설명하면, 자바 컴파일러는
    SuperClass sc=new SubClass(); 이러한 코드를 컴파일 할 때, "SubClass 클래스가 SuperClass 클래스를 상속했으니 이건 가능해!" 라고 판단하고 컴파일을 정상적으로 진행합니다.
    그러나, 이후부터는 참조변수 sc 가 비록 부모 클래스의 참조변수이지만, 실제로는 자식 객체를 참조한다는 사실을 기억하지 못합니다.
    여기서부터 약간의 고민이 필요하죠.
    질문자님이 컴파일러라면 sc.test(); 이 코드를 컴파일 할 때, 참조변수 sc 가 어떤 객체를 참조한다고 간주하시겠나요? 부모 객체? 자식 객체?
    자식 객체라고 간주해버리면, 만약 SubClass2 , SubClass3 이라는 클래스가 SuperClass 클래스를 상속했을 땐 어떻게 처리하시겠나요?
    하지만, 부모 객체라고 간주하면, 간단합니다.
    모든 자식 객체는 부모 객체의 모든 맴버를 가집니다.
    sc 가 실제로 어떤 자식 객체를 참조하건, 부모 객체의 맴버는 반드시 가지고 있다는 보장이 있기 때문에 컴파일러는 sc 가 부모 객체를 참조한다고 간주하고 호출하려는 메소드를 부모 클래스에서 찾는겁니다.


    2
  • 4books
    10
    2018-12-07 19:34:39

    엔카나님 정말 감사합니다. 가려운 곳을 정말 시원하게 긁어주셨어요 ㅎㅎ 

    다시 한번 더 감사드립니다.

    0
  • 로그인을 하시면 답변을 등록할 수 있습니다.