在 Java 中绑定(覆盖方法和 "fields")

Binding in Java (overriding methods and "fields")

public class Print1 {
    int x = 1;
    public void print(A a) { System.out.println(x); }
    public void print(B b) { System.out.println(x+1); }
}      

public class Print2 extends Print1 {
    int x = 3;
    public void print(A a) { System.out.println(x); }
    public void print(B b) { System.out.println(x+1); }
    public void print(C c) { System.out.println(x+2); }
}

// a tester class with main method 
A a = new A(); B b = new B(); C c = new C();
Print1 p1 = new Print1();
Print2 p2 = new Print2();
p1 = p2;

 System.out.println(p1.x); // Call 1, p1 is from Type Print1
 p1.print(c); /* Call 2
 //p1 is from Type Print2, print(B b) will be called */`

Class B 是 Class A 的子类,C 是 B 的子类。

  1. 为什么在类型 Print1 的调用 1 P1 中,即使它引用的是类型 Print2 的对象,而在调用 2 中它的行为是对Print2-对象?

  2. 为什么调用 2 print(B b) 是从 Print2 而不是 print(C c) 调用的?

这是迄今为止 Java 中让我最困惑的事情。谢谢您的帮助。

由于 可变阴影,首次打印如预期工作。

您有一个变量 p1(类型 Print1)指向堆上类型 Print2 的对象。因为 Print2 继承自 Print1 这是允许的。并且您能够访问 Print1 的变量 x 因为变量没有多态性,它们不能彼此 "override" 。您的变量类型决定了您要获取的 x

如果您在 Print1 class 中添加另一个变量 int y 会减少混淆。您可以毫无问题地以 System.out.println(p1.y); 访问它。


由于多态性(通过继承),第二个也按预期工作。

因为print(c)方法是在一个对象上执行的,对象显然是Print2类型(不管变量类型是什么(Print1Print2 ), 您将使用 Print2 的方法。只是因为 Print2 的方法覆盖了 Print1 的方法。

变量的类型用于确定访问的class成员。

因此 p1.x 指的是 Print1 中的 x 字段,而不是 Print2 中的字段。 (如果从 Print1 中删除 x,将导致编译时错误。)Print2 中的 x 字段是不同的字段,即 Print2对象有 2 个不同的 int 字段。

在表达式 p1.print(c) 中也使用了 print(B b) 方法,因为 Print1 没有方法 print(C c)。 (如果 C 不会扩展 BA,这将是一个编译时错误。)由于 Print2 覆盖了 Print1.print(B b) 的实现,该实现被使用了。