在 Dart 中,成员变量本身不能被覆盖。然而,你可以通过继承和重写方法来达到类似的效果。类的成员变量可以被子类隐藏,但这种行为通常不建议使用,因为这会导致代码的可读性和维护性降低。
隐藏成员变量
子类可以通过声明一个同名的成员变量来隐藏父类中的成员变量。这种方式被称为“隐藏”,而不是“覆盖”。
示例
假设我们有一个 Vehicle
类,它有一个名为 speed
的成员变量。
class Vehicle { int speed = 60; // 初始速度为60 void printSpeed() { print("Vehicle speed: $speed"); } }
现在我们创建一个 Car
子类,并且也定义了一个 speed
成员变量。
class Car extends Vehicle { int speed = 80; // Car的速度为80 @override void printSpeed() { print("Car speed: $speed"); } }
在这个例子中,Car
类中的 speed
变量隐藏了 Vehicle
类中的 speed
变量。当你尝试访问 Car
实例中的 speed
变量时,实际上是访问到了 Car
类中定义的那个 speed
变量。
访问隐藏的变量
尽管子类可以隐藏父类的变量,但你仍然可以通过父类的引用访问到父类中的变量。例如:
// javascriptcn.com 代码示例 void main() { Vehicle vehicle = Vehicle(); Car car = Car(); print(vehicle.speed); // 输出: 60 print(car.speed); // 输出: 80 // 使用父类类型的引用访问子类实例 Vehicle carAsVehicle = car; print(carAsVehicle.speed); // 输出: 80 }
在这里,即使 carAsVehicle
是一个 Vehicle
类型的引用,它实际上指向的是 Car
类的一个实例。因此,访问 speed
变量时,实际输出的是 Car
类中定义的那个变量的值。
方法覆盖
虽然成员变量不能被覆盖,但方法是可以被覆盖的。这是通过使用 @override
注解来实现的。方法覆盖允许子类提供一个与父类中同名方法不同的实现。
示例
继续使用上面的例子,Vehicle
类有一个 printSpeed
方法。
class Vehicle { int speed = 60; void printSpeed() { print("Vehicle speed: $speed"); } }
Car
类重写了这个方法:
class Car extends Vehicle { int speed = 80; @override void printSpeed() { print("Car speed: $speed"); } }
调用覆盖的方法
当你调用子类实例中的 printSpeed
方法时,实际执行的是子类中定义的那个方法。
void main() { Vehicle vehicle = Vehicle(); Car car = Car(); vehicle.printSpeed(); // 输出: Vehicle speed: 60 car.printSpeed(); // 输出: Car speed: 80 }
这里可以看到,当调用 car.printSpeed()
时,实际上执行的是 Car
类中定义的 printSpeed
方法,而并非 Vehicle
类中的那个方法。
总结
- 成员变量不能被覆盖,但可以通过隐藏来改变其可见性。
- 方法可以被覆盖,从而改变子类的行为。
- 使用
@override
注解可以明确地表明一个方法是被覆盖的。 - 当父类引用指向子类实例时,调用的方法或访问的变量取决于实际对象的类型,而不是引用的类型。