这是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'方法... 这是为了准备Java认证而进行的练习。 最好的问候
答案 0 :(得分:1)
对象类型(不是引用类型)确定在运行时使用哪个overriden方法/
A a = new B();
a.print();// this would always call B's print() in case of overriden methods
答案 1 :(得分:1)
有一件事是您用来访问对象的引用,另一件事是对象的实际类型。这是基本的subtype polymorphism。
您的对象属于B类,因为这是您创建的对象(即新B())。现在,您碰巧通过类型A的引用访问您的对象,这是可能的,因为B 是 A(B扩展A)。
当您通过引用调用方法 print 时,运行时类型系统知道即使引用是A类型,引用指向的实际对象也是B类,因此,它首先在B中查找 print 方法。那是那个被调用的那个,它解释了你看到的输出。
您的 print 方法就是他们所说的virtual method。这意味着运行时系统只根据运行时调用的目标对象的性质来确定调用该方法的所有实现的哪个实现。
现在,有了这个清楚,你在B中的重写实现就是被调用的东西。 重写实现不会自动触发父类中的实现。这与构造函数中的行为有些不同(它们不能被继承但可以链接)。
所以,这基本上意味着如果从你的overriden方法中你想要访问父类的行为,你必须让你的超类去做(即super.print())
因此,如果您正在处理构造函数,例如以下情况
class A {
public A() { System.out.println("A"); }
}
class B extends A{
public B() { System.out.println("B"); }
}
如果你创建一个B的实例,你应该看到A的输出。因为构造函数是自动链接的,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。
答案 2 :(得分:1)
请勿在{{1}}的构造中调用print
。这是打印A
的位置,因为0
的实例显然尚未完全初始化,B
的值显然仍为B.i
。
0
的隐式构造函数是:
B
如您所见,打印在public B() {
super(); // invokes B.print!
this.i = Math.round(3.5f);
}
初始化之前执行。然而,你已经覆盖了i
,旧的印刷品从未被执行过。
答案 3 :(得分:0)
当你在一个对象上调用一个方法时,它总是使用该对象的实际类型的实现,即使它是从一个超类中调用的。