在 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 变量。
访问隐藏的变量
尽管子类可以隐藏父类的变量,但你仍然可以通过父类的引用访问到父类中的变量。例如:
// www.javascriptcn.com code example
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注解可以明确地表明一个方法是被覆盖的。 - 当父类引用指向子类实例时,调用的方法或访问的变量取决于实际对象的类型,而不是引用的类型。