-1

这是Java语言的代码:

class A{
   A() {  print();   }
   void print() { System.out.println("A"); }
}
class B extends A{
   int i =   Math.round(3.5f);
   public static void main(String[] args){
      A a = new B();
      a.print();
   }
   void print() { System.out.println(i); }
}

它打印0, 4。但是为什么从构造函数中的超类 A 调用子类 print 方法呢?我看到 print 方法被覆盖了,但实际上已经从超类中调用了 'print' 方法......那是为了准备 Java 认证的练习。最好的祝福

4

4 回答 4

1

对象类型(不是引用类型)确定在运行时使用哪个覆盖方法/

A a = new B();
a.print();// this would always call B's print() in case of overriden methods 
于 2012-11-04T15:50:33.983 回答
1

一件事是您用来访问对象的引用,另一件事是对象的实际类型。这是基本的亚型多态性

您的对象属于 B 类型,因为那是您创建的(即 new B())。现在,您碰巧通过类型 A 的引用访问您的对象,这是可能的,因为 BA(B 扩展 A)。

当您通过引用调用方法print时,运行时类型系统知道即使引用是 A 类型,引用指向的实际对象也是 B 类型,因此它首先在 B 中查找方法print。那就是当时被调用的那个,它解释了你看到的输出。

您的print方法就是他们所说的虚拟方法。这意味着运行时系统仅根据运行时调用的目标对象的性质来确定将调用方法的所有实现的哪个实现。

现在,清楚地知道,您在 B 中的覆盖实现就是被调用的内容。被覆盖的实现不会自动触发父类中的实现。这与构造函数中的行为有些不同(不能被继承但可以被链接)。

所以,这基本上意味着,如果你想从你的重写方法访问父级的行为,你必须让你的超类去做(即 super.print())

因此,如果您正在处理构造函数,例如以下情况

class A {
   public A() { System.out.println("A"); }
}

class B extends A{
  public B() { System.out.println("B"); }
}

如果您创建 B 的实例,您应该看到 A B 的输出。因为构造函数是自动链接的,并且 B 中的构造函数调用 A 中的构造函数。

但在虚拟方法的情况下,您需要显式链接执行(如果这是您想要的),如下所示:

class A {
   public A() { System.out.println("A"); }
   //virtual method
   public void print(){ System.out.println("A"); }
}

class B extends {
  public B() { System.out.println("B"); }
   //virtual method overriden
   @Override
   public void print(){ 
      super.print(); //invokes A.print
      System.out.println("B"); 
   }
}

...为了查看输出 A B。

于 2012-11-04T15:53:06.137 回答
1

不要print在. _ _ A这是它打印的地方0,因为B显然的实例还没有完全初始化,而B.i显然仍然的值是0

隐式构造函数B

public B() {
   super(); // invokes B.print!
   this.i = Math.round(3.5f);
}

如您所见, print 在i初始化之前执行。然而,你已经覆盖print了,旧的打印永远不会被执行。

于 2012-11-04T15:54:36.180 回答
0

当你调用一个对象的方法时,它总是使用对象实际类型的实现,即使它是从超类中调用的。

于 2012-11-04T15:49:44.517 回答