Java 多态实例如何选择其方法?

Java 多态实例如何选择其方法?,java,polymorphism,overriding,overloading,Java,Polymorphism,Overriding,Overloading,我无法理解这段代码的行为。 a被定义为a,c被定义为c。 然后,在公共类的末尾,a=c。 当a调用display()方法时,它会到达它的C版本。 但是当a调用f()时,它只到达a版本,尽管第一个参数(byte和long)比float更符合long 这是一本书中的练习,但解释很少,或者根本不存在 A类{ 公共空间显示(){ System.out.println(“我是A”); } 公共空间f(双x){ System.out.println(“A.f(double=“+x+”)); } } C类扩展

我无法理解这段代码的行为。 a被定义为a,c被定义为c。 然后,在公共类的末尾,a=c。 当a调用display()方法时,它会到达它的C版本。 但是当a调用f()时,它只到达a版本,尽管第一个参数(byte和long)比float更符合long

这是一本书中的练习,但解释很少,或者根本不存在

A类{
公共空间显示(){
System.out.println(“我是A”);
}
公共空间f(双x){
System.out.println(“A.f(double=“+x+”));
}
}
C类扩展了{
公共空间显示(){
System.out.println(“我是C”);}
公共空间f(长q){
System.out.println(“C.f(long=“+q+”));}
}
公共级多管炮{
公共静态void main(字符串参数[]){
字节bb=1;长q=4;浮点x=5.f;
System.out.println(“**A**”);
A=新的A();A.显示();
a、 f(bb);a.f(x);
System.out.println();
System.out.println(“**C**”);
C=新的C();C.显示();
c、 f(bb);c.f(q);c.f(x);
System.out.println();
a=c;a.显示();
a、 f(bb);a.f(q);a.f(x);
}
} 
当调用
a.f(bb)
a.f(q)
a.f(x)
时,编译器可以选择的唯一方法签名是类
a
中定义的签名(或
a
的任何超类),因为
a
a
类型的参考变量

因此,仅考虑
公共无效f(双x)
。为了使
public void f(long q)
成为重载解析的候选,您必须在调用
f()
之前将
a
转换为键入
C
,因为只有类
C
定义了具有该签名的方法


需要理解的重要一点是,方法重载解析发生在编译时。只有为其调用方法的引用变量的编译时类型才能确定哪些方法签名是方法重载解析的候选项,以及将选择哪个候选项。

编译器选择的方法取决于声明的类型,而不是运行时类型。
声明为变量
A
的第一个系列只能调用一个方法(无论实例化为
A
的运行时类型仅派生
对象
):

对于第二个系列,由于
C
a
,因此编译器可以在此处绑定与调用匹配的最特定参数的方法,因此编译器可以绑定这些方法中的任何公共方法:

C c = new C(); 
c.f(bb); c.f(q); c.f(x);   
但在最后一段可能会问你自己的代码中,
a
C
称为运行时对象,而将
a
称为声明类型:

A a = new A(); 
// ...
a = c; 
a.f(bb); a.f(q); a.f(x);

因此,只能调用
A
中定义的方法

我会尽量澄清一下@eran的答案,这样你就可以理解它了

一个子类拥有它的超类的所有方法,也许还有更多的方法。您有一个
a
类型的变量,其中存储了
C
类型的对象
C
包含类
A
中定义的所有方法,还有一个附加方法,即
f(长q)
A
不知道这个新方法,因此由于将对象存储在变量
A
中,因此不能调用
f(长q)


但是,您可以调用
display()
,因为它是在
A
中定义的,但它仍然是执行它的
C
对象。

我刚刚在另一个论坛上发现:

重载:(相同的函数名但不同的签名)

  • 在同一类中,两个或多个具有相同名称和不同片段的方法称为重载

  • 当您想要扩展功能时,将使用重载

  • 重载称为编译时多态性

  • 重写:(相同的函数名,但签名相同)

  • 父类和子类中具有相同方法名和相同片段的两个或多个方法称为重写

  • 当您希望重用现有函数时,将使用重写

  • 重写称为运行时多态性

  • 因此,我的问题的答案似乎是重写解析(如display())发生在运行时(这里是在a=c之后),而重载解析(如f())发生在编译时,此时a仍然是a

    我想

    我还发现了这个页面:


    清楚且与本主题高度相关。

    您本可以提供一个更好的示例,删除所有不必要的代码以使其最小化(请参阅),但这仍然是一个有趣的问题。我不知道答案,但我担心这将是一个重复的问题。所以换句话说,发生这种情况是因为
    display()
    在编译时是可确定的,而
    f()
    不是吗?@Gendarme
    display()
    f(双x)
    在编译时都是可确定的(当方法调用是针对类型a的变量时)。但是,在
    display()的情况下
    ,方法重写在运行时起作用-因为C有一个具有相同签名的
    display
    方法,如果
    a
    引用类
    C
    ,则执行
    C
    display
    方法,而不是
    a
    的方法“编译器可以选择的唯一方法签名是在类A(或A的任何超类)中定义的方法签名”为什么它在C中调用display?因为
    C
    覆盖
    display()
    ,而它只重载
    f()
    ,@Tchae.@Gendarme,那么A只能
    A a = new A(); 
    // ...
    a = c; 
    a.f(bb); a.f(q); a.f(x);