在 Java 中,重写(Override) 是指子类提供父类中已有的方法的具体实现。这是面向对象编程中多态性的一个重要体现,允许子类根据需要自定义或扩展从父类继承的行为。要正确地重写一个方法,必须满足以下几个条件:
1. 方法签名必须相同
- 方法名、参数列表(包括参数的数量和类型顺序)必须与父类中的方法完全一致。
- 返回类型也必须相同,或者是在协变返回类型的情况下,可以是父类方法返回类型的子类型(Java 5 及以上版本支持)。
2. 访问修饰符不能更严格
- 子类中重写的方法的访问修饰符不能比父类中的方法更严格。例如,如果父类方法是
public
,那么子类方法也应该是public
或者protected
,但不能是private
。
3. 不能抛出新的检查异常
- 子类方法不能抛出新的或更广泛的检查异常(checked exceptions),但可以抛出更少或更具体的异常。
4. 使用 @Override
注解
- 虽然不是强制性的,但在子类方法前添加
@Override
注解是一个良好的实践。它不仅有助于代码的可读性,还可以让编译器帮助检查是否确实存在被重写的方法,从而避免拼写错误等问题。
在这个例子中,Animal里有两个方法,一个eat和一个drink,Dog里重写了 Animal类的 eat方法,并自己有一个lookHome方法,在Test里new 一个Dog()的时候,会有两种写法:
Dog dog = new Dog(); Animal animal = new Dog();
dog可调用到三个方法,分别是重写的eat、父类的drink、自己的lookHome
animal可调用到两个方法,eat和drink,需要注意到的是,eat是子类重写后的方法,并不是父类中原来的方法。
当通过 Animal
类型的引用调用 eat方法时,实际执行的是子类中定义的方法,这体现了多态性。
协变返回类型
从 Java 5 开始,允许重写方法具有不同的返回类型,只要它是父类方法返回类型的子类型。例如:
class Parent {
Object getObject() {
return new Object();
}
}
class Child extends Parent {
@Override
String getObject() { // 协变返回类型:String 是 Object 的子类型
return "Child's string";
}
}
注意事项
- 静态方法不能被重写:静态方法属于类而不是实例,因此它们不会表现出多态行为。如果子类定义了一个与父类静态方法同名的方法,那实际上是隐藏了父类的方法,而不是重写。
- 构造函数也不能被重写:构造函数用于创建对象,并且每个类都有自己的构造函数,所以不存在构造函数重写的情况。
- 私有方法不能被重写:因为私有方法仅限于声明它的类内部使用,所以它们不能被子类访问或重写。但是,子类可以定义一个相同名称的方法,但这并不是真正的重写,而是隐藏了父类的方法。