理解Java的继承模型

时间:2015-09-07 06:29:35

标签: java inheritance

示例代码:

public class Parent {
  String name = "Parent";

  public String getName() {
    return this.name;
  }
}

public class Child extends Parent {
  String name = "Child";

  public String getName() {
    return this.name;
  }
}

public class Tester {
  public static void main (String[] args) {
    Parent p = new Child();
    Child  c = new Child();
    System.out.println("p.name is " + p.name); // prints out "Parent"
    System.out.println("c.name is " + c.name); // prints out "Child"
    System.out.println("p.getName() is " + p.getName()); // prints out "Child"
    System.out.println("c.getName() is " + c.getName()); // prints out "Child"
  }
}

我的理解到目前为止

到目前为止,我对Java继承的理解使我能够理解为什么第3和第4 println个语句产生“Child”作为输出。在编译时,编译器确保在引用变量的类型中定义getName方法,但在运行时期间确定了哪个版本getName。由于两个引用变量实际上都引用了Child对象,因此调用了Child getName

问题1

但是,为什么直接访问实例变量时,行为与访问方法的方式不同?特别是,我发现奇怪p.name返回“父”而不是“孩子”。

问题2

与此类似,如果我在getName类中注释掉Child函数并重新运行Tester中的代码,我会惊讶地发现{{1} }和p.getName()返回“Parent”而不是“Child”。

有人可以帮助详细说明这两个问题吗?

1 个答案:

答案 0 :(得分:4)

无法在Java中覆盖变量。您所做的事情被称为隐藏变量(name中的变量Parent难以访问)

理解您所描述的行为的方法是将name视为变量的名称,而不是实际的变量。当在Parent的上下文中使用时(在代码方面,而不是变量的实际类型),它指向与在Child的上下文中使用时不同的变量。

调用c.namep.name时,告诉程序要使用哪个上下文,因为变量cp分别声明为Child类型, Parent。在类中的方法中使用它时,使用当前类的变量。

如果您想在子课程中使用Parent.name,则必须进行投射:

System.out.println("c.name is " + ((Parent) c).name);

对于方法,调用的函数始终是被调用变量的实际类型。在您的情况下,无论是从TesterParent还是Client调用它。

当然最好不要隐藏变量,对不同的变量使用不同的名称。