正如本站的这篇Java中的重载(Overload)与重写(Override)所述,Java作为一门高级的、面向对象的语言,其具有多态性,而多态性的背后原理就是类的方法的重写机制。那么,Java中类的属性是否也可以重写呢?本文将带领大家来一起探寻答案。
实验代码
在编程界有一句名言:Talk is cheap, show me the code。所以,我们废话少说,直接来分析一段示例代码,这段代码会创建出两个子类对象:其中一个被赋值给了一个子类引用;另一个被赋值给了一个父类引用。
class Super {
String strA = "www.tiantianbianma.com";
}
class Sub extends Super {
String strA = "天天编码";
}
public class FieldOverRide {
public static void main(String[] args) {
Sub subA = new Sub();
System.out.println(subA.strA);
Super superA = new Sub();
System.out.println(superA.strA);
}
}
强烈建议大家仔细思考得出答案后,实际上机验证,正确的输出结果是:
天天编码
wwww.tiantianbianma.com
代码中,我们创建了两个Sub对象,但是,两个对象的输出结果却完全不同,什么原因呢?
原理分析
实际上,在Java的规范中,Java对于类的方法和属性采用了两种完全不同的处理机制:对于方法,使用重载机制实现了多态性;对于属性,使用的是同名属性隐藏机制。所谓的同名属性隐藏机制是指:在具有父子关系的两个类中,子类中相同名字的属性会使得从父类中继承过来的同名属性变得不可见,不管类型是否一致,名称一致的两个属性就是同名属性。在子类中,无法简单地通过属性名称来获取父类中的属性,而是必须通过父类名称加属性名称(Super.strA)的方法才可以访问父类中的该属性。一般而言,为了代码容易阅读,极其不建议在父类和子类中使用同名属性。
从上面的示例代码和Java规范分析中,我们可以知道:类的属性成员不能像方法成员一样被重写。当一个子类定义了一个与父类同名的属性,实际上就是子类定义了一个新的属性成员,该属性同时隐藏了父类中的同名属性。因为属性的不可重写性,也就没有属性的多态性质,所以示例代码中的 superA.StrA 表达式的值是在编译器就依照类型 superA 来求值。
总结
在已经存在同名属性隐藏的情况下,如何使得子类可以访问父类中的同名属性呢?本文为大家总结了两个方法:
1. 通过使用父类型的引用变量,参考本文的示例代码。
2. 通过强制向上转型,示例代码如下:
System.out.println(((Super)subA).strA);