Java父类引用调用子类变量和方法返回不同结果的原因
为什么父类引用访问成员变量和调用重写方法结果不一致
这个差异本质是Java对成员变量和实例方法采用了完全不同的绑定规则,和多态的生效范围直接相关:
成员变量不支持多态,访问时走静态绑定
子类声明和父类同名的成员变量时,不会覆盖父类的同名字段,只会发生字段隐藏:一个子类实例的内存中,会同时存在父类定义的x和子类自己定义的x两个独立的变量,互不干扰。
直接通过.访问成员变量时,访问哪个字段完全由引用的声明类型决定,和引用实际指向的对象类型无关。你的代码中myPig、myDog的声明类型都是Animal,所以直接访问.x时,永远取的是Animal类中定义的x=10。实例方法支持运行时多态,调用时走动态绑定
子类重写父类的实例方法时,会发生方法覆盖:方法调用的目标在程序运行时才确定,依据是引用指向的实际对象类型,和引用的声明类型无关。
当你调用myPig.getX()时,JVM识别到myPig实际指向的是Pig类实例,就会执行Pig类中重写的getX()方法,这个方法返回的是Pig类自己定义的x=20;同理myDog.getX()会执行Dog类的重写方法,返回x=30。
补充验证:如果你把
Pig类中的getX()方法删掉,再调用myPig.getX()就会返回10——此时调用的是从Animal继承来的getX()方法,该方法作用域内访问的x是父类Animal中定义的字段。
如果要在子类方法中访问被隐藏的父类同名字段,可以使用super.x语法。
测试代码
class Animal { int x = 10; public int getX() { return x; } public void animalSound() { System.out.println("The animal makes a sound"); } } class Pig extends Animal { int x = 20; public int getX() { return x; } public void animalSound() { System.out.println("The pig says: wee wee"); } } class Dog extends Animal { int x = 30; public int getX() { return x; } public void animalSound() { System.out.println("The dog says: bow wow"); } } class Main { public static void main(String[] args) { Animal myAnimal = new Animal(); Animal myPig = new Pig(); Animal myDog = new Dog(); myAnimal.animalSound(); System.out.println(myAnimal.getX()); System.out.println(myAnimal.x); myPig.animalSound(); System.out.println(myPig.getX()); System.out.println(myPig.x); myDog.animalSound(); System.out.println(myDog.getX()); System.out.println(myDog.x); } }
运行输出
The animal makes a sound 10 10 The pig says: wee wee 20 10 The dog says: bow wow 30 10
内容的提问来源于stack exchange,提问作者user2755407
相关产品推荐
相关产品推荐

