我很难理解这段代码的行为。 a定义为A,c定义为C。 然后,在公开课结束时,a = c。 当调用display()方法时,它将达到C的版本。 但是,当a调用f()时,尽管第一个参数(字节和长整数)与long兼容而不是float,但它仅达到A版本。
这是书中的练习,但解释很少或不存在。
class A{
public void display(){
System.out.println("I am an A ");
}
public void f(double x){
System.out.println("A.f(double = " + x + ") ");
}
}
class C extends A{
public void display(){
System.out.println("I am a C ");}
public void f(long q){
System.out.println("C.f(long = " + q + ") ");}
}
public class PolySurStack{
public static void main(String Args[]){
byte bb =1; long q = 4; float x = 5.f;
System.out.println(" ** A **");
A a = new A(); a.display();
a.f(bb); a.f(x);
System.out.println();
System.out.println(" ** C **");
C c = new C(); c.display();
c.f(bb); c.f(q); c.f(x);
System.out.println();
a = c; a.display();
a.f(bb); a.f(q); a.f(x);
}
}
答案 0 :(得分:1)
当您调用a.f(bb)
或a.f(q)
或a.f(x)
时,编译器可以选择的唯一方法签名是类A
中定义的方法签名(或{ {1}}),因为A
是类型a
的引用变量。
因此,仅考虑A
。为了使public void f(double x)
成为重载解决方案的候选者,您必须在调用public void f(long q)
之前强制转换a
以键入C
,因为只有类f()
定义具有该签名的方法。
要了解的重要一点是方法重载解析是在编译时发生的。只有调用了该方法的参考变量的编译时类型才能确定哪些方法签名是方法重载解决方案的候选对象,以及将选择哪种候选方法。
答案 1 :(得分:1)
我刚刚在另一个论坛上找到了这个
重载:(函数名称相同,但签名不同)
在同一个类中具有相同名称和不同延展性的两个或多个方法称为重载。
要扩展功能时使用重载。
重载被称为编译时多态性
覆盖:(相同的函数名称,但签名相同)
在父类和子类中具有相同方法名称和相同性的两个或多个方法,称为覆盖。
要重用现有功能时使用覆盖。
重载被称为运行时多态性
所以我的问题的答案似乎是,在运行时(这里,在a = c之后)出现了压倒性的分辨率(例如display()),而在编译时发生了重载的分辨率(例如,对于f()),当a仍然是A。
我想。
我还找到了此页面:https://beginnersbook.com/2013/04/runtime-compile-time-polymorphism/
明确且与此主题高度相关。
答案 2 :(得分:0)
编译器选择的方法取决于声明的类型,而不取决于运行时类型。
声明为变量A
的第一个系列只能调用A方法(无论实例化为A
的运行时类型仅源自Object
):
A a = new A();
a.f(bb); a.f(x);
对于第二个系列,由于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
中定义的方法。
答案 3 :(得分:0)
我会尝试澄清@eran的答案,以便您理解。
子类具有其超类的所有方法,然后可能还有其他一些方法。您具有类型A
的变量,其中存储了类型C
的对象。 C
具有类A
中定义的所有方法,还有一个附加方法f(long q)
。 A
不知道这种新方法,因此,由于将对象存储在变量A
中,因此无法调用f(long q)
。
您可以 调用display()
,因为它是在A
中定义的,但是它仍然是执行它的C
对象。