【发布时间】:2015-09-07 06:29:35
【问题描述】:
示例代码:
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 继承的理解让我理解了为什么第三和第四个 println 语句会产生“Child”作为输出。在编译时,编译器确保 getName 方法在引用变量的类型中定义,但在运行时确定哪个版本 getName。由于两个引用变量实际上都引用了一个Child 对象,因此调用了 Child 的getName。
问题 1
但是,为什么当你直接访问实例变量时,行为与访问方法的方式不同呢?特别是,p.name 返回的是“Parent”而不是“Child”,这让我感到很奇怪。
问题 2
类似地,如果我在 Child 类中注释掉 getName 函数并重新运行 Tester 中的代码,我会惊讶地看到 p.getName() 和 c.getName() 返回 "父”而不是“子”。
有人可以帮忙详细说明这两个问题吗?
【问题讨论】:
-
您所遇到的整个问题是您认为您也可以覆盖变量,但您不能。检查this
-
感谢@KevinEsche 分享此链接!这如何适用于我的第二个问题?
-
此外,继承描述了一个 is a 关系。出于这个原因,
Parent/Child的类比非常糟糕。Child不是Parent。 -
@wmock,因为同名的变量不会使它们在逻辑上连接。函数 get name 不会查找名称为
name的变量。它具体指的是它在定义方法的类中找到的 on(或者它在可见性范围内继承的任何类) -
你了解静态类型和运行时类型的区别吗? (
p有静态类型Parent和运行时类型Child和c有静态类型Child和运行时类型Chald。)编译器 决定了哪个字段访问,即字段访问取决于静态类型。 (如果你查看编译后的字节码,p.name将引用Parent.name。)VM 决定调用哪个方法,即方法访问取决于运行时类型。
标签: java inheritance