Java向上转型子类对象为何变量用父类、方法用子类?附构造器疑问
Java继承常见问题解答
1. 向上转型后方法调用与变量访问的差异原因
这是因为Java中方法调用是动态绑定,而变量访问是静态绑定:
- 方法
speak()被Dog类重写了,当通过向上转型的引用beagle调用时,JVM会在运行时根据实际对象的类型(Dog)选择执行子类的重写方法。 - 变量
legs在Dog类中是重新定义的(属于变量隐藏,Java不支持变量重写),编译期会根据引用的编译类型(Animal)确定访问哪个变量,所以beagle.legs访问的是Animal类中未初始化的legs(默认值0)。
2. 构造器执行两次的原因
每次创建子类对象时,Java会隐式调用父类的无参构造器:
- 子类构造器的第一行默认会执行
super()(编译器自动添加,无需手动编写),所以每次new Dog()都会先执行Animal的构造器,再执行Dog的构造器。 - 你创建了2个Dog对象,因此Animal和Dog的构造器各被调用2次,对应输出里的四行构造器日志。
3. Animal dog = new Dog(); 中各部分的含义
Animal是引用变量dog的编译类型:它决定了编译阶段这个引用能调用哪些方法(比如只能调用Animal类中定义或继承的方法)。new Dog()是实际创建的对象的运行类型:这个对象本质是Dog实例,运行时的方法执行、对象属性的实际存储都由这个类型决定。
示例代码
// Online Java Compiler // Use this editor to write, compile and run your Java code online class Animal { int legs; Animal(){ //this.legs = 5; System.out.println("-- Animal Constructor called --"); } void speak(){ System.out.println("Speak!"); } } class Dog extends Animal { int legs; Dog(){ this.legs = 4; System.out.println("-- Dog Constructor called --"); } void speak(){ System.out.println("Bow wow!"); } } class Main { public static void main(String[] args) { Animal beagle = new Dog(); Dog chew_wawa = new Dog(); // Animal animal = new Animal(); System.out.println(beagle.legs); System.out.println(chew_wawa.legs); // System.out.println(animal.legs); beagle.speak(); chew_wawa.speak(); // animal.speak(); } }
代码输出
-- Animal Constructor called -- -- Dog Constructor called -- -- Animal Constructor called -- -- Dog Constructor called -- 0 4 Bow wow! Bow wow! Process finished with exit code 0
内容的提问来源于stack exchange,提问作者ZaneK
相关产品推荐
相关产品推荐

