
本文旨在深入探讨Java中子类使用`super`关键字修改父类实例属性时的行为。核心内容在于澄清实例变量的作用域,强调每个对象实例(包括父类和子类实例)都拥有其独立的实例变量副本。通过分析具体代码示例,我们将详细解释`super.variable`如何作用于当前子类实例继承的属性,以及为何它不会影响其他独立父类实例的同名属性,从而纠正关于`super`关键字和实例变量作用域的常见误解。
在Java面向对象编程中,继承是实现代码复用和多态性的重要机制。子类可以继承父类的属性和方法。然而,当子类尝试通过super关键字修改父类定义的实例属性时,常常会产生一些关于作用域和对象实例的误解。本教程将通过一个具体的示例来详细阐释这一行为。
理解实例变量与对象实例
首先,我们需要明确“实例变量”这一概念。实例变量是属于对象而不是类本身的变量。这意味着每当我们创建一个类的新实例(即一个对象)时,这个新实例都会拥有自己一套独立的实例变量副本。即使这些变量是在父类中定义的,子类实例继承后,它所操作的也是自己这份副本。
super关键字在子类中用于引用父类的成员(包括方法和变量)。当我们在子类中使用super.variable时,它实际上是指向当前子类实例所继承的那个父类变量副本。它并不会去访问或修改任何其他独立的父类对象实例的变量。
立即学习“Java免费学习笔记(深入)”;
示例代码分析
让我们通过以下Java代码示例来具体分析:
package Practice.FruitConst;
public class App {
public static void main(String[] args) {
Fruit fruit = new Fruit(); // 1. 创建一个Fruit对象实例
Apple apple = new Apple(); // 2. 创建一个Apple对象实例
apple.setPrice(100.0); // 3. 调用Apple实例的setPrice方法
apple.pp(); // 4. 调用Apple实例的pp方法
System.out.println("fruit " + fruit.price); // 5. 打印Fruit实例的price
}
}
class Apple extends Fruit {
@Override
public void setPrice(Double price) {
super.price = price; // 6. 修改当前Apple实例继承的price属性
}
public void pp() {
System.out.println("apple " + this.price); // 7. 打印当前Apple实例的this.price
System.out.println("fruit? " + super.price); // 8. 打印当前Apple实例的super.price
}
}
class Fruit {
String name;
String color;
double price; // 9. 定义实例变量price,默认值为0.0
// 省略 toString, getter, setter 方法,它们与本例核心无关
public void setPrice(Double price) {
this.price = price;
}
}按照代码执行顺序,我们来逐步分析变量price的变化:
-
Fruit fruit = new Fruit();
- JVM创建了一个Fruit类的对象实例,并将其引用赋值给fruit变量。
- 这个fruit对象拥有自己的实例变量price,其默认值为0.0。
-
Apple apple = new Apple();
- JVM创建了一个Apple类的对象实例,并将其引用赋值给apple变量。
- 由于Apple继承自Fruit,所以这个apple对象也拥有自己继承来的实例变量price,其默认值为0.0。
- 注意: 此时,fruit对象的price和apple对象的price是两个完全独立的变量。
-
apple.setPrice(100.0);
- 调用apple对象(一个Apple类的实例)的setPrice方法。
- 进入Apple类中重写的setPrice方法:super.price = price;
- 这里的super.price指的是当前apple对象实例所继承的price属性。因此,apple对象的price属性被更新为100.0。
- 关键点: 这个操作只影响apple对象的price,对fruit对象的price没有任何影响。
-
apple.pp();
- 调用apple对象的pp方法。
- System.out.println("apple " + this.price);
- this.price指的是当前apple对象的price属性,此时为100.0。
- 输出:apple 100.0
- System.out.println("fruit? " + super.price);
- super.price同样指的是当前apple对象所继承的price属性,此时也为100.0。
- 输出:fruit? 100.0
- 注意: 在子类实例内部,this.price和super.price通常指向同一个物理内存位置,即当前子类实例继承的那个属性。只有当子类中定义了与父类同名的实例变量(即变量隐藏,不推荐)时,它们才可能不同。
-
System.out.println("fruit " + fruit.price);
- 打印fruit对象的price属性。
- fruit对象的price从未被修改过,因此它仍然是初始值0.0。
- 输出:fruit 0.0
综合以上分析,程序的实际输出将是:
apple 100.0 fruit? 100.0 fruit 0.0
这与问题中观察到的输出完全一致。
总结与注意事项
- 实例变量的独立性: Java中每个对象实例都拥有其独立的实例变量副本。即使它们继承自同一个父类,不同对象实例之间的同名实例变量也是相互独立的。
- super关键字的作用域: 在子类中,super.variable用于访问当前子类实例所继承的父类属性。它不会影响其他独立的父类对象实例的同名属性。
- 理解对象引用: Fruit fruit = new Fruit(); 和 Apple apple = new Apple(); 创建了两个完全不同的对象实例,它们在内存中占据不同的位置,彼此独立。
- 避免混淆: 初学者常会将super理解为“访问父类对象”,但实际上它只是“访问当前对象中继承自父类的成员”。
通过本教程的讲解,希望能帮助您更清晰地理解Java中super关键字、实例变量作用域以及对象实例独立性的概念,从而避免在继承关系中操作属性时产生的常见误解。










