104. Java 继承 - 实例方法的覆盖
在 Java 中,子类可以覆盖(重写)从父类继承来的实例方法。覆盖意味着子类提供了一个新的实现来替代父类中继承的方法。为了使方法覆盖有效,子类中的方法必须与父类中的方法具有相同的签名:方法名称、参数的数量和类型以及返回类型。
方法覆盖
当子类中存在与父类相同签名的实例方法时,子类的方法会覆盖父类中的方法。这个能力允许子类从父类继承足够接近的行为,然后根据需要修改这些行为。
例如:
java
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.sound(); // 输出:Dog barks
}
}
在上面的例子中,Dog
类覆盖了 Animal
类中的 sound()
方法。即使 myDog
变量被声明为 Animal
类型,实际调用的是 Dog
类中重写后的 sound()
方法。这是因为 Dog
类重写了父类 Animal
中的 sound()
方法。
协变返回类型(Covariant Return Types)
当子类覆盖父类方法时,子类可以改变方法的返回类型,只要返回类型是父类方法返回类型的子类型。这样的返回类型被称为 协变返回类型(Covariant Return Type)。
例如:
java
class Animal {
public Animal getAnimal() {
return new Animal();
}
}
class Dog extends Animal {
@Override
public Dog getAnimal() {
return new Dog();
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal();
Dog myDog = new Dog();
Animal a = myAnimal.getAnimal(); // 返回类型是 Animal
Dog d = myDog.getAnimal(); // 返回类型是 Dog
}
}
在上面的代码中,Animal
类的 getAnimal()
方法返回 Animal
类型,而 Dog
类覆盖了该方法,并返回 Dog
类型,这就是协变返回类型的应用。Java 允许子类方法返回比父类方法更加具体的类型。
使用 @Override 注解
虽然 Java 支持方法覆盖,但为了确保程序员的意图明确且避免错误,推荐使用 @Override
注解。@Override
注解告诉编译器我们打算覆盖父类中的方法。如果子类中的方法签名不正确(例如,方法名不匹配或参数数量和类型不一致),编译器将抛出错误。使用 @Override
注解可以帮助我们在编译时发现这些错误,从而避免不必要的运行时错误。
java
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
在这个示例中,@Override
注解确保了我们确实覆盖了 Animal
类中的 sound()
方法。如果我们在 Dog
类中错误地拼写方法名或改变方法签名,编译器将会提示错误。
常见错误
如果您尝试覆盖父类中不存在的方法,编译器会在使用 @Override
注解时给出错误。例如:
java
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void bark() { // 编译错误,因为没有 "bark" 方法
System.out.println("Dog barks");
}
}
在这个例子中,Dog
类尝试用 @Override
注解覆盖 bark()
方法,但 Animal
类并没有定义 bark()
方法。因此,编译器会提示错误:"无法找到符号"。
总结
- 方法覆盖:子类可以覆盖父类中的实例方法,覆盖方法必须与父类方法的签名(方法名、参数数量和类型、返回类型)一致。
- 协变返回类型:子类在覆盖父类方法时,返回类型可以是父类返回类型的子类类型。
- @Override 注解 :
@Override
注解用于标记方法覆盖,确保方法签名与父类方法一致。如果不一致,编译器将报错,避免潜在的运行时错误。 - 覆盖时的常见错误 :如果子类方法不符合父类方法签名,编译器会报错。通过使用
@Override
注解可以及时捕获这种错误。
通过这些例子和解释,您可以更好地理解 Java 中的实例方法覆盖,以及如何正确使用 @Override
注解,确保方法覆盖的正确性。