多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# java 中的方法覆盖 > 原文: [https://beginnersbook.com/2014/01/method-overriding-in-java-with-example/](https://beginnersbook.com/2014/01/method-overriding-in-java-with-example/) 声明**子类**中已经存在于**父类**中的方法称为方法覆盖。完成覆盖,以便子类可以将自己的实现提供给父类已经提供的方法。在这种情况下,父类中的方法称为覆盖方法,子类中的方法称为覆盖方法。在本指南中,我们将看到 Java 中的方法覆盖是什么以及我们使用它的原因。 ## 方法覆盖示例 让我们举一个简单的例子来理解这一点。我们有两个类:一个子类`Boy`和一个父类`Human`。 `Boy`类扩展了`Human`类。这两个类都有一个共同的方法`void eat()`。`Boy`类给`eat()`方法赋予了自己的实现,换句话说它覆盖了`eat()`方法。 方法覆盖的目的在这里很清楚。`Child`类想要给出自己的实现,这样当它调用这个方法时,就会打印出`Boy`正在吃而不是`Human`正在吃东西。 ```java class Human{ //Overridden method public void eat() { System.out.println("Human is eating"); } } class Boy extends Human{ //Overriding method public void eat(){ System.out.println("Boy is eating"); } public static void main( String args[]) { Boy obj = new Boy(); //This will call the child class version of eat() obj.eat(); } } ``` 输出: ```java Boy is eating ``` ## 方法覆盖的优点 方法覆盖的主要优点是类可以为继承的方法**提供自己的特定实现,甚至不需要修改父类代码**。 当一个类有多个子类时,这很有用,所以如果一个子类需要使用父类方法,它可以使用它,而其他想要具有不同实现的类可以使用覆盖功能进行更改而不触及父类码。 ## 方法覆盖和动态方法调度 方法覆盖是[运行时多态](https://beginnersbook.com/2013/04/runtime-compile-time-polymorphism/)的示例。当父类引用指向子类对象时,则在运行时确定对覆盖方法的调用,因为在方法调用期间,要执行哪个方法(父类或子类)由对象类型确定。在运行时解析对覆盖方法的调用的过程称为动态方法调度。让我们看一个例子来理解这个: ```java class ABC{ //Overridden method public void disp() { System.out.println("disp() method of parent class"); } } class Demo extends ABC{ //Overriding method public void disp(){ System.out.println("disp() method of Child class"); } public void newMethod(){ System.out.println("new method of child class"); } public static void main( String args[]) { /* When Parent class reference refers to the parent class object * then in this case overridden method (the method of parent class) * is called. */ ABC obj = new ABC(); obj.disp(); /* When parent class reference refers to the child class object * then the overriding method (method of child class) is called. * This is called dynamic method dispatch and runtime polymorphism */ ABC obj2 = new Demo(); obj2.disp(); } } ``` 输出: ```java disp() method of parent class disp() method of Child class ``` 在上面的示例中,使用第二个对象(`obj2`)调用 `disp()`方法是运行时多态(或动态方法调度)。 **注意**:在动态方法调度中,对象可以调用子类的覆盖方法和基类的所有非覆盖方法,但是它不能调用子类中新声明的方法。在上面的例子中,对象`obj2`正在调用`disp()`。但是,如果您尝试使用`obj2`调用`newMethod()`方法(已在`Demo`类中新声明),那么您将使用以下消息给出编译错误: ```java Exception in thread "main" java.lang.Error: Unresolved compilation problem: The method xyz() is undefined for the type ABC ``` ## Java 中的方法覆盖规则 1. 参数列表:覆盖方法的参数列表(子类的方法)必须与被覆盖方法(父类的方法)匹配。参数的数据类型及其序列应完全匹配。 2. 覆盖方法(子类方法)的[访问修饰符](https://beginnersbook.com/2013/05/java-access-modifiers/)不能比父类的重写方法更具限制性。例如,如果父类方法的访问修饰符是`public`,则覆盖方法(子类方法)不能具有`private`,`protected`和`default`访问修饰符,因为所有这三个访问修饰符都比`public`更具限制性。 例如,这是**不允许**的,因为子类`disp`方法比基类(`public`)更具限制性(`protected`)。 ```java class MyBaseClass{ public void disp() { System.out.println("Parent class method"); } } class MyChildClass extends MyBaseClass{ protected void disp(){ System.out.println("Child class method"); } public static void main( String args[]) { MyChildClass obj = new MyChildClass(); obj.disp(); } } ``` 输出: ```java Exception in thread "main" java.lang.Error: Unresolved compilation problem: Cannot reduce the visibility of the inherited method from MyBaseClass ``` 然而,这是完全有效的情况,因为公众的限制性比受保护的要少。相同的访问修饰符也是有效的。 ```java class MyBaseClass{ protected void disp() { System.out.println("Parent class method"); } } class MyChildClass extends MyBaseClass{ public void disp(){ System.out.println("Child class method"); } public static void main( String args[]) { MyChildClass obj = new MyChildClass(); obj.disp(); } } ``` 输出: ```java Child class method ``` 3. `private`,`static`和`final`方法不能被覆盖,因为它们是类的本地方法。但是,静态方法可以在子类中重新声明,在这种情况下,子类方法的行为会有所不同,并且与父类的相同静态方法无关。 4. 覆盖方法(子类的方法)可以抛出[非受检的异常](https://beginnersbook.com/2013/04/java-checked-unchecked-exceptions-with-examples/),无论被覆盖的方法(父类的方法)是否抛出任何异常。然而,最重要的方法不应该抛出[检查的异常](https://beginnersbook.com/2013/04/java-checked-unchecked-exceptions-with-examples/),这些异常是新的或比被覆盖方法声明的异常更宽。我们将在即将到来的教程中使用示例详细讨论这个问题。 5. 覆盖方法的绑定在运行时发生,称为[动态绑定](https://beginnersbook.com/2013/04/java-static-dynamic-binding/)。 6. 如果一个类正在扩展[抽象类](https://beginnersbook.com/2013/05/java-abstract-class-method/)或实现[接口](https://beginnersbook.com/2013/05/java-interface/),那么它必须覆盖所有抽象方法,除非该类本身是一个抽象类。 ## 方法覆盖中的`super`关键字 [`super`关键字](https://beginnersbook.com/2014/07/super-keyword-in-java-with-example/)用于调用父类方法/构造函数。 `super.myMethod()`调用基类的`myMethod()`方法,而`super()`调用基类的[构造函数](https://beginnersbook.com/2013/03/constructors-in-java/)。让我们看一下在方法覆盖使用`super`。 我们知道我们覆盖子类中的方法,然后使用子类对象调用该方法调用覆盖方法。通过使用`super`,我们可以调用覆盖方法,如下例所示: ```java class ABC{ public void myMethod() { System.out.println("Overridden method"); } } class Demo extends ABC{ public void myMethod(){ //This will call the myMethod() of parent class super.myMethod(); System.out.println("Overriding method"); } public static void main( String args[]) { Demo obj = new Demo(); obj.myMethod(); } } ``` 输出: ```java Class ABC: mymethod() Class Test: mymethod() ``` 如您所见,使用`super`关键字,我们可以访问覆盖的方法。