Java继承场景下静态变量调用结果不符合预期问题咨询
问题产生原因
- Java中的静态成员属于类本身,不属于实例对象,不存在重写机制,子类中定义的同名静态变量只是「隐藏」了父类的静态变量,而非重写。
- 静态成员的访问解析在编译阶段就完成,只看变量的声明类型,不看运行时的实际类型。你循环中变量
animal的声明类型是Animal,所以不管运行时实际是Dog还是Cat实例,animal.DEFAULT_NAME都会被解析为Animal.DEFAULT_NAME,因此输出全为anymal。 - 你的需求和
Serializable接口没有关联,该接口是Java用于序列化的标记接口,和静态成员的访问逻辑无关。 - IDE提示子类应当定义对应静态变量,是因为这种隐藏父类静态成员的写法极易导致你遇到的预期不符问题,属于不推荐的编码方式,IDE在做风险提醒。
解决方法
推荐使用实例方法实现多态,这是最符合Java面向对象设计的方案:
给父类定义非静态的取值方法,子类重写该方法返回对应的值,静态变量可以保留在类内部作为常量使用,不需要对外暴露:
public class Animal { private static final String DEFAULT_NAME = "anymal"; public String getDefaultName() { return DEFAULT_NAME; } } public class Dog extends Animal { private static final String DEFAULT_NAME = "doggy"; @Override public String getDefaultName() { return DEFAULT_NAME; } } public class Cat extends Animal { private static final String DEFAULT_NAME = "caddy"; @Override public String getDefaultName() { return DEFAULT_NAME; } }
修改Main类的循环逻辑,调用实例方法即可得到预期输出:
for (Animal animal : animals) { System.out.println(animal.getDefaultName()); }
如果确实有需要直接关联类静态变量的场景,也可以用反射实现,但不推荐日常使用(性能差、无编译期校验,漏写变量会直接抛出运行时异常):
for (Animal animal : animals) { try { System.out.println(animal.getClass().getField("DEFAULT_NAME").get(null)); } catch (Exception e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

