看了这篇文章:
https://www.ibm.com/developerworks/cn/java/j-lo-polymorph/
有一些疑问。
class Person {
public String toString(){
return "I'm a person.";
}
public void eat(){}
public void speak(){}
}
class Boy extends Person{
public String toString(){
return "I'm a boy";
}
public void speak(){}
public void fight(){}
}
class Girl extends Person{
public String toString(){
return "I'm a girl";
}
public void speak(){}
public void sing(){}
}
//最后这么用的话,
Person girl = new Girl();
girl.speak();
按照作者的说法,girl引用变量指向堆中的 Girl对象,所以运行的时候知道当前对象是Girl对象,找Girl的方法表,
找到后执行。这对于speak方法来说是行得通的。
但是如果这样呢:
girl.sing();
按照作者的说法,去Girl方法表找到sing方法,然后执行。
实际情况大家都知道有错误,编译不通过。
这中间肯定漏了点我不知道的什么?希望可以赐教。
换个方式问也就是:
当发生向上转型的时候,栈和堆中分别发生了什么?
소스 코드는 이렇게 생겼습니다. 아직 생략된 부분이 있습니다. 이제 코드가 이렇게 생겼으니
Person girl = new Girl()
girl을 넣지 마세요. .speak( )
이 두 문장은 수업시간에 직접 호출하면 구조가 틀려요
호출할 수 있는 메서드를 결정하는 것은 변수가 가리키는 힙에 있는 개체의 실제 유형이 아니라 변수의 선언된 유형 입니다.
당신을 좋아합니다:
으아악girl
의 선언 유형은Person
이고,Person
에는speak
메서드가 없으므로 오류가 보고됩니다. 이는 컴파일러가 보고한 컴파일 시간 오류입니다. 컴파일러는girl
이 어떤 유형으로 실행되는지 상관하지 않습니다.런타임 동안 가상 머신은 물론
girl
에 의해 실행된 힙의 개체가Girl
유형이라는 것을 알게 됩니다.컴파일러는 선언된 변수 유형에 따라 메소드 호출 가능 여부를 결정하는 이유는 무엇입니까? 그 이유 중 하나는 컴파일하는 동안 이 변수가 런타임에 어떤 유형의 개체에 바인딩되어 있는지 전혀 알 수 없기 때문입니다. 예:
으아악이 예에서
p
는 런타임까지 바인딩된 개체의 실제 유형을 확인할 수 없습니다.주제의 질문은 다형성 개념과 관련이 있습니다. 설명을 위해 주제의 예를 사용해 보겠습니다.
주제별로 정의된 세 가지 클래스
으아악Person
,Girl
,Boy
를 사용한다고 가정합니다. 언제객체
ps
를 정의한 후 컴파일 시 해당 유형은Person
이지만 런타임 시 실제 유형은Girl
입니다.
으아악ps
개체를 사용할 때 프로그램은 그것이Person
이라는 것만 알고Person
에는eat
과speak
의 두 가지 메서드만 있으므로 개체 멤버를 호출할 때eat
및speak
두 메서드만 호출합니다. 프로그램은ps
개체의 실제 유형이Girl
인지 모르므로Girl
의 고유한sing
메서드를 호출할 수 없습니다. 즉,그러면 프로그램은
ps
객체의 실제 동적 유형이Girl
인지 알지 못하는데 왜ps.speak();
가 여전히Girl
에서 구현을 호출할 수 있습니까? 이것이 다형성이 하는 일입니다.하위 클래스를 가리키는 상위 클래스 포인터/참조의 경우 상위 클래스 메서드가 하위 클래스에서 재정의된 경우 이 메서드가 상위 클래스 포인터/참조를 통해 호출되면 컴파일러는 상위 클래스 포인터/참조를 추가합니다. 컴파일하는 동안 클래스 메서드 호출은 실제 유형의 메서드에 동적으로 바인딩됩니다. 하위 클래스에 의해 재정의되지 않은 메서드는 부모 클래스의 메서드에 정적으로 바인딩됩니다.
이는 추상적인 관점에서 이해됩니다. 하위 수준 구현 방법은 특정 구현을 참조해야 하며, 이는 주제에서 제공하는 기사에서 더 명확하게 설명됩니다.
스택은 사람, 힙은 소녀, 사람 클래스는 노래 방법에 대한 참조가 없습니다.