Java 为什么动态绑定和只调用父类中的子方法的设计不同?

Java 为什么动态绑定和只调用父类中的子方法的设计不同?,java,polymorphism,subclass,superclass,dynamic-binding,Java,Polymorphism,Subclass,Superclass,Dynamic Binding,我知道在重写方法的情况下,Java遵循动态绑定。但是,如果我们从父引用变量调用一个仅限子对象的方法(该变量引用子对象),则会出现编译错误。 为什么java遵循这种设计(即为什么在第二种情况下没有动态绑定)? class A{ public void sayHi(){ "Hi from A"; } } class B extends A{ public void sayHi(){ "Hi from B"; public void sayGoodBye(){ "Bye

我知道在重写方法的情况下,Java遵循动态绑定。但是,如果我们从父引用变量调用一个仅限子对象的方法(该变量引用子对象),则会出现编译错误。
为什么java遵循这种设计(即为什么在第二种情况下没有动态绑定)?

class A{
    public void sayHi(){ "Hi from A"; }
}


class B extends A{
    public void sayHi(){ "Hi from B"; 
    public void sayGoodBye(){ "Bye from B"; }
}


main(){
  A a = new B();

  //Works because the sayHi() method is declared in A and overridden in B. In this case
  //the B version will execute, but it can be called even if the variable is declared to
  //be type 'A' because sayHi() is part of type A's API and all subTypes will have
  //that method
  a.sayHi(); 

  //Compile error because 'a' is declared to be of type 'A' which doesn't have the
  //sayGoodBye method as part of its API
  a.sayGoodBye(); 

  // Works as long as the object pointed to by the a variable is an instanceof B. This is
  // because the cast explicitly tells the compiler it is a 'B' instance
  ((B)a).sayGoodBye();

}

在动态分派方法调用之前,代码必须经过编译器。当您使用类
C
的引用调用方法时,编译器会在该类
C
中查找该方法的声明。编译器只关心引用类型是什么。它只能在这么多信息上验证方法调用。如果在类
C
中找不到该方法,它将给您提供编译器错误

因此,对于调用:

a.sayGoodBye(); 

由于
a
是类
a
的引用,编译器将在类
a
中查找方法,如果找不到,它将给出编译器错误。

B
a
,但
a
B
。所以
B
的方法不能在
A
reference

上调用,请这样想:当B扩展A时;这意味着

B = <All non-private stuff of A> + Its own stuff

B=

但是在方法重写的情况下它正在发生。但是为什么在重写A的情况下可以访问B的方法定义呢?我没有得到“重写A”的东西?你能添加一个覆盖A和访问B方法的例子吗?如果您在示例中谈到第二个案例失败,那是因为在编译时,引用的类型是A;因此,只有A的方法是可见的。如果您知道A确实在B上保留了一个引用,那么您需要使用强制转换来告诉编译器。由于B是a的子级,所以B上的任何引用都不需要强制转换,因为编译器肯定知道B是a(因此它的行为可以类似于a)。请查看调用
a.sayHi()
时打印的内容。这称为运行时绑定。老实说,编译器从来不知道它会在运行时以B对象结束我们。它只知道引用的类型是A,并且A有一个名为sayHi()的方法。。这一切都令人高兴。编译器从不知道有一个类B重写了sayHi();实际上它不在乎。。它只是检查您是否正在调用一个方法,该方法是否属于引用类型。继续…从上次评论继续。。。。因为在运行时,对象被更改,并且它持有该方法(继承或重写);该方法已被执行。如果B不会覆盖A的sayHi();它最终将执行A的方法,但在运行时它遵循动态绑定。这意味着我可以说,对于调用
a.sayHi()
compile,请尝试在a中查找
sayHi()
声明,因为它存在,所以没有错误。然后在运行时,根据对象(即内存地址)调用对象,并且存在C对
sayHi()
的定义,因此调用它。对于方法
saybye
,当您在编译时得到错误时(如您所解释的),应该不存在在运行时调用哪个定义的问题。@knoxhs。没错。当代码甚至没有编译时,运行时的行为是没有问题的。