Java中子类和父类存在同名属性时的运行机制疑问
Java父子类同名属性调用规则解析
你提供的测试代码如下:
public class Test { public static void main(String[] args) { B b = new B(); b.test(); } } class A { String aString = "a"; void test() { System.out.println(aString); } } class B extends A { String aString = "b"; }
核心结论
Java中属性不存在重写机制,只有隐藏特性,方法才支持重写(动态分派),这是出现该输出的根本原因。
具体运行规则
- 方法调用的动态分派:你调用
new B().test()时,因为B类没有重写父类A的test()方法,所以实际执行的是A类中定义的test()方法逻辑。 - 属性引用的静态绑定:类方法中引用的属性,是在编译期就和当前方法所属的类绑定的,不会根据调用方法的实例类型动态切换。A类的
test()方法中的aString,编译时就已经绑定为A类自己的aString属性,值为"a",因此最终输出为"a"。 - 子类同名属性的本质:B类定义的
aString只是隐藏了父类的同名属性,并非覆盖。B类的实例在内存中实际上会保留两份aString属性,分别属于父类A和子类B。如果要在子类代码中访问父类的同名属性,需要用super.aString显式指定,但父类方法中不会主动访问子类定义的同名属性。
拓展:如何实现输出"b"的预期效果
方案1:子类重写test()方法
class B extends A { String aString = "b"; @Override void test() { // 该方法属于B类,编译期绑定B类的aString属性 System.out.println(aString); } }
方案2:使用getter方法利用动态分派特性
属性是静态绑定,但方法是动态分派的,因此可以通过定义公共的getter方法实现预期效果:
class A { String aString = "a"; // 定义getter方法 public String getaString() { return aString; } void test() { // 调用getter方法,会根据实例类型动态分派 System.out.println(getaString()); } } class B extends A { String aString = "b"; // 重写getter方法 @Override public String getaString() { return aString; } }
以上两种方案执行new B().test()都会输出"b"。
内容的提问来源于stack exchange,提问作者levartsang
相关产品推荐
相关产品推荐

