请告诉我们输出的原因。
按照我的说法,使用b.getx()我们将获得B对象的引用ID,b.getx().x
应该得到10的值,但是当我运行这个程序时,输出为5。
class Base {
int x = 5;
public Base getx() {
return new Base();
}
}
class Child extends Base {
int x = 10;
public Child getx() {
return new Child();
}
public static void main(String ...s) {
Base b = new Child();
System.out.println(b.getx().x);
}
}
答案 0 :(得分:8)
字段访问(与方法调用不同)不受运行时动态调度的影响,它们仅基于编译时类型进行解析。
变量b
属于编译时类型Base
,因此b.getx()
也是编译时类型Base
,因此b.getx().x
将是编译成Base的x
字段的访问权限,而不是Child的。通过查看javap
方法main
的输出来确认:
public static void main(java.lang.String[]);
Code:
0: new #3; //class Child
3: dup
4: invokespecial #4; //Method "<init>":()V
7: astore_1
8: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokevirtual #6; //Method Base.getx:()LBase;
15: getfield #7; //Field Base.x:I
18: invokevirtual #8; //Method java/io/PrintStream.println:(I)V
21: return
您可以看到b.getx().x
专门编译为getfield
Base.x
指令。
答案 1 :(得分:1)
动态绑定基本上意味着实际调用的方法实现是在运行时确定的,而不是在编译时确定的。这就是为什么它被称为动态绑定 - 因为将在运行时选择将运行的方法。动态绑定也称为后期绑定。
答案 2 :(得分:1)
Base b = new Child();
在运行时解析,并且通过动态绑定规则(运行时多态性),所有与此相关的方法都应该在运行时绑定,所以......
public Base getx() {
return new Base();
}
这些行返回基类的新实例,你只是在该实例上调用了变量。
答案 3 :(得分:0)
动态绑定是在运行时查看声明的运行时时间过程。它也称为后期绑定,其中对重写方法的调用在运行时而不是编译时解析。 在面向对象的系统方法中,覆盖(动态多态)在运行时完成。当用一种方法覆盖另一种方法时,两种方法的签名必须相同。
示例:强>
class Animal{
public void eat(){
System.out.println("Animals voice");
}
public void go(){
System.out.println("Animals can walk");
}
}
class Dog extends Animal{
public void go(){
System.out.println("Dogs can walk and run");
}
public void eat(){
System.out.println("Dogs can eat a wide range of foods");
}
}