示例代码:
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”。
有人可以帮助详细说明这两个问题吗?
答案 0 :(得分:4)
无法在Java中覆盖变量。您所做的事情被称为隐藏变量(name
中的变量Parent
难以访问)
理解您所描述的行为的方法是将name
视为变量的名称,而不是实际的变量。当在Parent
的上下文中使用时(在代码方面,而不是变量的实际类型),它指向与在Child
的上下文中使用时不同的变量。
调用c.name
或p.name
时,告诉程序要使用哪个上下文,因为变量c
和p
分别声明为Child
类型, Parent
。在类中的方法中使用它时,使用当前类的变量。
如果您想在子课程中使用Parent.name
,则必须进行投射:
System.out.println("c.name is " + ((Parent) c).name);
对于方法,调用的函数始终是被调用变量的实际类型。在您的情况下,无论是从Tester
,Parent
还是Client
调用它。
当然最好不要隐藏变量,对不同的变量使用不同的名称。