具有超类函数性的子类对象



我很困惑为什么这个代码能工作。对象";人;被声明为只具有A功能的B的实例,但它不知何故打印了两次hello。如果对象只能访问A中的方法,那么它怎么会访问print out语句呢?

abstract class A {
abstract void move();
void go() {
this.move();
}
}
class B extends A {
void move() {
System.out.println("hello");
}
}
public class Main {
public static void main(String[] args){
A person = new B();
person.move();
person.go();
}

不,您有一个"链接";属于类A,但功能取决于对象(在您的代码中,它是新的B((;(,所以你的A链接指向一个具有B功能的B对象。

对象"人;被声明为仅具有功能的B的实例

不完全是。Java是一种基于参考的语言;在这里,您已经创建了一个实例(new B()(,并且只有一个引用,称为person

您可能没有对它的引用(导致创建的对象最终被垃圾收集(。你可以有2000个对它的引用。你可以有B b = new B(); A a = b;,现在你有2个对它,一个是类型A,一个类型B。但它们指向的是完全相同的对象。

因此,person不是一个对象,而是一个引用。当然,该引用的类型是A,但它引用的对象只是一个B,它不被"限制"为只有a功能。

你可能知道这一切,但术语在这里很重要,因为它似乎导致了一些混乱。用不那么含糊的术语重述你的问题:

引用";人;当前引用了B的一个实例,但只公开了A具有的功能。

是。A的功能仅由存在的签名来描述,而不是由代码来描述。A的功能包括一个go()方法,它不接受任何参数,也不返回任何内容,以及一个具有相同规则的move()方法仅此而已-"调用go将实际运行move方法",或者"move没有实现">不属于

因此,move()go()都是A.公开的功能的一部分

功能的实现与引用类型(A person(无关,一切都与引用实际指向的内容(new B()(有关。B对A指定的move((和go((方法的实现使得CCD_;你好";,go()调用move(因此,打印hello(((-该实现是从A继承的,但B可以自由更改;然而,B决定不这样做。

更严格地说:

Java使用一种名为动态调度的东西。这意味着,在编译时(即写入时(,java会判断出您调用的方法是否存在,以及哪个变体(如果您有move(String a)move(int a),这是两个同名的方法,在写入时,java会决定您试图调用哪一个(,并使用点前的表达式类型来判断。但在运行时,"点前面的表达式"实际指向的对象的实际类型用于确定要调用的实际代码。这种情况总是会发生,并且你不能选择退出(当你调用main()时,你不能选择运行A的实现。只有B的实现可以选择不覆盖A的实现,或者显式调用其超类型的实现。B代码的用户不能这样做(。

请注意,static的东西根本不"做"继承,因此,动态调度不适用于此。

最新更新