4

请告诉我们得到输出的原因。

根据我的说法,使用 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);
  }
}
4

4 回答 4

8

字段访问(与方法调用不同)不受运行时动态调度的影响,它们纯粹基于编译时类型进行解析。

该变量b是编译时类型的Base,因此b.getx()也是编译时类型Base的,因此b.getx().x将被编译为对 Basex字段的访问,而不是 Child 的。通过查看javapformain方法的输出可以确认这一点:

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

于 2013-05-15T15:35:32.717 回答
1

动态绑定基本上意味着实际调用的方法实现是在运行时确定的,而不是在编译时确定的。这就是为什么它被称为动态绑定——因为将要运行的方法是在运行时选择的。动态绑定也称为后期绑定。

于 2014-03-15T08:18:35.870 回答
1

Base b = new Child();是在运行时解决的,并且通过动态绑定规则(运行时多态性)所有与之相关的方法都应该在运行时绑定,所以......

public Base getx() {
    return new Base();
  }

这些行返回基类的新实例,而您刚刚在该实例上调用了变量。

于 2017-10-27T14:08:58.033 回答
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");
   }
}
于 2014-05-01T07:03:21.330 回答