java中覆盖、重写与重载的区别

本文详细解析了Java中的override(方法覆盖)与overload(方法重载)的概念及应用区别。通过具体示例说明了如何正确使用这两种特性,并列举了在实际编程中需要注意的关键点。
原文: http://blog.chinaunix.net/uid-12926986-id-111709.html

初次见到这两个单词并没有什么特别的感觉,但是时间长了,却发现书上一会儿用override,一会儿又用overload,搞得我的迷迷糊。于是就做了个总结,希望能对和我一样对这两个概念模糊不清的网友有一个帮助。
     override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点:
    1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
    2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
    3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
    4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
     overload对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点:
    1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int));
    2、不能通过访问权限、返回类型、抛出的异常进行重载;
    3、方法的异常类型和数目不会对重载造成影响;
    下面是对override和overload的测试程序,其中注释中的内容都是会产生编译错误的代码,我们将注释去掉,看看在编译时会产生什么效果。
// 对overload测试的文件:OverloadTest.java
public class OverloadTest {
 // 下面几个方法用来验证可以通过定义不同的参数类型和参数的数目进行方法重载。
 public void fun(){
   System.out.println("method fun in OverloadTest, no parameter");
 }

 public void fun(float f) {
   System.out.println("method fun in OverloadTest, parameter type: float");
 }
    
 public void fun(int i){
   System.out.println("method fun in OverloadTest, parameter type: int");
 }

 public void fun(int i1, int i2) {
   System.out.println("method fun in OverloadTest, parameter type: int, int");
 }
    
 // 下面的两个方法用来验证可以通过定义不同的参数顺序进行方法重载。
 // 需要注意:这里的参数肯定不是相同的类型,否则的顺序的先后就毫无意义。
 public void fun1(int i, float f) {
   System.out.println("method fun1 in OverloadTest, sequence of parameters is: int, float");
 }

 public void fun1(float f, int i) {
   System.out.println("method fun1 in OverloadTest, sequence of parameters is: float, int");
 }

 // 下面的两个方法用来验证方法抛出的异常对于重载的影响. // 无论是异常的类型还是异常的个数都不会对重载造成任何的影响。 public void fun2() throws TestException {    System.out.println("fun2 in OverloadTest, exception: TestException"); } public void fun2(int i) throws TestException, TestException1 {    System.out.println("fun2 in OverloadTest, exception: TestException, TestException1"); } public void fun2(float f) throws Exception {    System.out.println("fun2 in OverloadTest, exception: Exception"); } // 不能通过抛出的异常类型来重载fun方法。 //public void fun(int i) throws Exception { // System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception"); //}     // ? 不能通过返回值重载fun方法。 //public boolean fun(int i) throws Exception { // System.out.println("method fun in OverloadTest, parameter type: int, exception: Exception, return: boolean"); // return true; //} private void fun3() { } // 不能通过不同的访问权限进行重载 public void fun3() { } public static void main(String[] args) {   // 这里只是定义了OverloadTest的实例,所以test不会调用   // OverloadTest1中的方法。    OverloadTest test = new OverloadTest1();   // 这里定义了OverloadTest1的实例,因为OverloadTest1是OverloadTest   // 的子类,所以test1会调用OverloadTest中的方法。    OverloadTest1 test1 = new OverloadTest1();   try {    int i = 1, j = 2, m = 3;    // 这里不会调用OverloadTest1的fun方法    // test.fun(i, m, j);     test1.fun(i, j, m);     test1.fun();    // 这个调用不会执行,因为fun3()在OverloadTest中访问权限是priavte     //test1.fun3();     test1.fun3(i);    } catch(Exception e) { } } } class OverloadTest1 extends OverloadTest{ // 在子类中重载fun public void fun(int i, int m, int n) {    System.out.println("Overload fun1 in OverloadTest1, parameter type: int, int, int"); } // 这个不是对父类中方法的重载,只是一个新的方法。 public void fun3(int i) {    System.out.println("fun2 in OverloadTest1"); } } // 对override测试的文件:OverrideTest.java public class OverrideTest { public void fun() throws TestException {    System.out.println("method fun in OverrideTest"); } private void fun1() {    System.out.println("method fun1 in OverrideTest"); } public static void main(String[] args) {    OverrideTest test = new OverrideTest1();   try {      test.fun();      test.fun1();    } catch(Exception e) { } } } class OverrideTest1 extends OverrideTest{ // 以下正常Override public void fun() throws TestException2 {    System.out.println("fun in OverrideTest1"); } // 不能Override父类中的方法,因为它定义了不同的异常类型和 // 返回值。 //public int fun() throws TestException1 { // System.out.println("method fun in Test"); // return 1; //}      // 不能Override父类中的方法,因为它抛出了比父类中非法范围 // 更大的异常。 //public void fun() throws Exception { // System.out.println("fun in OverrideTest1"); //} // 这个方法并没有Override父类中的fun1方法,因为这个方法在 // 父类是private类型,所以这里只是相当于定义了一个新方法。 public void fun1() {    System.out.println("method fun1 in Test"); } } class TestException extends Exception{ public TestException(String msg) {   super(msg); } } class TestException1 extends TestException { public TestException1(String msg) {   super(msg); } } class TestException2 extends TestException { public TestException2(String msg) {   super(msg); } }

<think>首先,用户的问题是:“我想了解Java重写重载的概念及区别请问Java重写重载区别”。所以,我需要基于系统级指令来回答。系统级指令包括:-所有行内数学表达式使用$...$格式。-独立公式使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识。另外,用户可见层指令:回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。参考的引用是关于Java重载重写区别,我应该利用这些信息,但确保回答准确。结构我的回答:1.**介绍概念**:先解释重写(Override)和重载(Overload)的基本概念。2.**详细解释区别**:使用清晰的列表或表格来比较它们的区别。3.**提供例子**:用代码示例来说明,增强理解。4.**引用标识**:在适当的地方添加引用标识。5.**生成相关问题**:在末尾添加相关问题。生成相关问题:根据系统指令,我需要生成相关问题,类似示例中的“§§相关问题§§”。现在,回顾参考引用:-引用[1]:简单介绍重载重写区别。-引用[2]:详细定义重写重载。-引用[3]:涉及底层实现(静态分派和动态分派)。-引用[4]:提供例子。我应该整合这些信息,确保回答真实可靠。回答结构:1.**开头**:简要介绍重写重载的概念。2.**主体**:-解释重载(Overload)。-解释重写(Override)。-比较关键区别(如范围、参数、多态性等)。-提供代码示例。3.**结尾**:总结区别。4.**相关问题**:添加相关问题。确保使用中文回答。数学表达式:由于主题是Java编程,可能不需要复杂的数学表达式,但如果有数值或简单数学,用$...$格式。例如,在解释参数类型时,或许不需要。添加引用:在回答中引用段落时,末尾添加[^n],如[^1]、[^2]等。参考引用有4个,我应该使用它们。最后,生成相关问题:例如:1.重载重写在多态中的作用是什么?2.如何避免重写时的常见错误?3.重载在方法签名中的限制是什么?现在,构建回答大纲:-步骤1:解释重载(Overload)-定义:方法名相同,但参数列表不同(个数、类型、顺序)。-例子:引用[4]中的计算器例子。-步骤2:解释重写(Override)-定义:子类继承父类并重写方法,方法签名相同。-例子:动物类中的声音方法。-步骤3:比较区别-范围重载在同一个类,重写在继承关系中。-参数:重载参数不同,重写参数相同。-多态性:重载是编译时多态(静态分派),重写是运行时多态(动态分派)。-权限:重写时子类方法权限不能小于父类。-步骤4:总结-步骤5:相关问题添加引用标识:例如,在解释重载时引用[2],在解释重写时引用[3]。确保语言自然流畅。</think>### Java重写重载的概念及区别Java编程中,重写(Override)和重载(Overload)都是多态性的表现形式,但它们在工作原理和应用场景上有本质区别。下面我将逐步解释这两个概念的核心定义、关键区别,并通过代码示例帮助你清晰理解。回答基于可靠的Java编程原理[^2][^3],确保内容真实可靠。 #### 1. **概念解释** - **重载(Overload)**:指在同一个类中,定义多个方法名相同但参数列表不同的方法。参数列表的差异体现在参数的数量、类型或顺序上。重载允许开发者用同一个方法名处理不同输入,提高代码复用性和灵活性。例如,一个计算器类可以定义多个`add`方法,分别处理整数、浮点数或可变参数[^4]。 - **重写(Override)**:指在继承关系中,子类重新定义父类中的方法,方法签名(方法名、参数列表和返回类型)必须完全相同。重写实现了运行时多态性,允许子类根据自身需求修改方法行为。例如,一个`Animal`父类有`sound()`方法,子类`Dog`可以重写该方法以输出特定叫声[^2][^3]。 #### 2. **关键区别** 下表总结了重写重载的核心差异(基于编译时和运行时的行为): | **特性** | **重载(Overload)** | **重写(Override)** | |----------------|-----------------------------------------------|-----------------------------------------------| | **范围** | 同一个类中 | 继承关系的子类父类之间 | | **参数列表** | 必须不同(数量、类型或顺序) | 必须完全相同 | | **返回类型** | 可以不同 | 必须相同(或子类返回类型兼容父类) | | **多态性类型** | 编译时多态(静态分派),由编译器根据参数类型决定调用哪个方法 | 运行时多态(动态分派),由JVM在运行时根据对象实际类型决定 | | **访问权限** | 无限制,方法权限可任意 | 子类方法权限不能小于父类(如父类`protected`,子类不能为`private`) | | **底层实现** | 编译时解析(静态分派),依赖方法签名 | 运行时解析(动态分派),指令如`invokevirtual` | 关键点: - **多态性**:重载是静态多态(如方法根据输入参数变化),重写是动态多态(如对象造型时父引用调用子类方法)[^3]。 - **错误处理**:重载不会覆盖方法,仅提供新版本;重写必须遵守父类契约,否则可能引发`@Override`注解错误或逻辑错误。 #### 3. **代码示例** 以下示例使用Java代码说明两者的实际应用(基于真实编程实践[^4])。 **重载示例**:同一个类中,方法名相同但参数不同。 ```java public class Calculator { // 重载add方法:整数加法 public int add(int a, int b) { return a + b; } // 重载add方法:浮点数加法 public double add(double a, double b) { return a + b; } // 重载add方法:可变参数求和 public int add(int... numbers) { int sum = 0; for (int num : numbers) { sum += num; } return sum; } } ``` 在这个例子中,调用`add(2, 3)`会匹配第一个方法,而`add(1.5, 2.5)`会匹配第二个方法。编译器在编译时根据参数类型决定调用哪个版本[^4]。 **重写示例**:子类重写父类方法。 ```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 myAnimal = new Dog(); // 父类引用指向子类对象 myAnimal.sound(); // 输出 "Dog barks",运行时决定调用子类方法 } } ``` 在这个例子中,`Dog`类重写了`sound()`方法。当父类引用`myAnimal`调用`sound()`时,JVM在运行时根据对象实际类型(`Dog`)执行重写后的方法,体现了动态多态性[^2][^3]。 #### 4. **总结** - **重载**:用于同一类中扩展方法功能,通过参数差异实现编译时多态。它简化了API设计,减少了方法名冗余。 - **重写**:用于子类修改父类行为,实现运行时多态。它支持继承和多态性,但必须严格遵守方法签名和访问权限规则。 两者共同提升了Java的灵活性和可维护性,用好它们能设计出结构清晰的类[^1]。在实际开发中,优先使用重载处理参数变化,重写则用于定制继承逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值