Java 中方法重载和重写之间的区别

培训教学 潘老师 8个月前 (09-01) 180 ℃ (0) 扫码查看

在Java面试中,方法重载和方法重写(即多态)的概念经常被考察。让我们通过一些易于理解的例子来深入理解它们的区别。

请记住,方法重载发生在同一个类中,而方法重写则发生在子类继承父类时

1.方法重载

方法重载是指在一个类中定义了两个同名的方法,在重载任何方法时,我们应该记住以下几个规则:

1.1 参数列表必须不同

重载方法的最重要的规则就是改变方法签名。方法签名包括参数的数量、参数的类型以及参数的顺序(如果有多个参数)。

在下面的例子中,方法sum()被定义了两次。两个方法都接受两个参数。第一个方法接受参数类型为Integer,第二个方法接受参数类型为Float和Integer。在这里,方法的参数数量相同,但是它们的类型不同。

//正确示例
public class Calculator {
  public Integer sum(Integer a, Integer b) {
    return a + b;
  }
  public Integer sum(Float a, Integer b) {
    return a.intValue() + b;
  }
}

1.2. 不考虑方法返回类型

方法的返回类型不属于方法签名,所以仅仅改变方法的返回类型并不能构成方法的重载,换句话说就是返回值类型与重载无关。

在下面的例子中,这些方法接受类似的参数但是它们的返回类型不同。这是一个无效的代码,并且会产生编译错误“sum(Integer, Integer) is already defined in  Calculator”。

//无法重载,直接报错
public class Calculator {
  public Integer sum(Integer a, Integer b) {
    return a + b;
  }
  public Double sum(Integer a, Integer b) {
    return new Double(a + b);
  }
}

1.3. 不考虑抛出的异常

在重载方法时,方法抛出的异常也不被考虑。所以如果重载的方法抛出相同的异常、不同的异常或者不抛出任何异常,都不会对方法重载产生任何影响。

//无法重载,直接报错
public class Calculator {
  public Integer sum(Integer a, Integer b) throws NullPointerException{
    return a + b;
  }
  public Integer sum(Integer a, Integer b) throws IllegalArgumentException{
    return a + b;
  }
}

2.方法重写

当子类重写父类的方法时,就会发生方法重写。在Java中重写方法时,请始终记住以下规则。

2.1 方法参数必须完全相同

被重写方法和重写方法中的方法参数列表必须完全相同。如果它们不匹配,那么我们相当于就创建了一个不同的方法。

在下面的例子中,Parent和Child类具有具有相同名称和完全相同参数列表的方法。这是一个有效的方法重写。

class Parent {
  public Integer sum(Integer a, Integer b) {
    return a + b;
  }
}
class Child extends Parent {
  public Integer sum(Integer a, Integer b) {
    return a + b;
  }
}

2.2 方法返回类型可以是子类型

重写方法的返回类型可以是声明在重写方法中的返回类型的子类。

在下面的例子中,父类中的方法的返回类型是Number,而在Child类中,它是Integer。这是一个有效的返回类型,因此被认为是有效的方法重写。

class Parent {
  public Number sum(Integer a, Integer b) {
    return a + b;
  }
}
class Child extends Parent {
  public Integer sum(Integer a, Integer b) {
    return a + b;
  }
}

如果我们使用Child类中的不兼容的返回类型,将会出现编译错误。

//编译错误
class Parent {
  public Number sum(Integer a, Integer b) {
    return a + b;
  }
}
class Child extends Parent {
  public String sum(Integer a, Integer b) {
    return a.toString() + b.toString();
  }
}

2.3 抛出的异常可以是子类中的子类型

覆盖方法不能抛出比被覆盖方法所抛出的更高级别的检查异常(即编译时异常)。

例如,Parent类中的被覆盖方法抛出FileNotFoundException,Child类中的覆盖方法可以抛出FileNotFoundException,但不允许抛出IOException或Exception,因为IOException或Exception在继承层次结构中更高。

//错误案例
class Parent {
  public String readFile(String file) throws FileNotFoundException {
    //...
    return null;
  }
}
class Child extends Parent {
  public String readFile(String file) throws IOException {
    //...
    return null;
  }
}

需要注意的是,我们可以从覆盖方法中省略异常声明,这是允许的,并且完全有效。此外,覆盖方法可以抛出任何未检查(运行时)异常,而不管被覆盖方法是否声明该异常。

在下面的示例中,覆盖方法省略了FileNotFoundException并声明了RuntimeException,这是一个未检查的异常。这是有效的方法覆盖。

// 正确示例
class Parent {
  public String readFile(String file) throws FileNotFoundException {
    //...
    return null;
  }
}
class Child extends Parent {
  public String readFile(String file) throws RuntimeException {
    //...
    return null;
  }
}

2.4 private、static和final方法不能被重写

在Java中,private、static和final方法不能以任何方式被重写。

  • private修饰符限制了该方法只能在本类中使用。
  • static成员属于类对象。
  • final关键字用于表示该成员不能被重写。

在下面的示例中,Parent和Child类声明了具有相同名称和参数的方法,但这并不是方法重写。readFile()方法永远不能在Parent类之外访问。

// 正确示例
class Parent {
  private String readFile(String file){
    //...
    return null;
  }
}
class Child extends Parent {
  public String readFile(String file) {
    //...
    return null;
  }
}

2.5 重写方法不能缩小访问范围

另外需要注意的是,重写方法不能缩小被重写方法的访问范围。

例如,如果父类中的被重写方法是protected,则子类中的重写方法不能是private。它必须是protected(相同访问)或public(更广泛的访问)。

// 正确示例
class Parent {
  protected String readFile(String file){
    //...
    return null;
  }
}
class Child extends Parent {
  public String readFile(String file) {
    //...
    return null;
  }
}

3. 如何验证方法重写是否正确

要验证我们是否正确地重写了方法,只需在子类中的重写方法上使用注解@Override。这将验证所有方法重写规则。如果重写存在任何问题,则将导致编译时错误。

class Parent {
  protected String readFile(String file){
    //...
    return null;
  }
}
class Child extends Parent {
  @Override
  public String readFile(String file) {
    //...
    return null;
  }
}

以上就是对Java重写和重载概念区别进行的深入讲解。

教程 Java基础教程

文章目录 前言  第1章 Java语言基础 第2章 流程控制语句 第3章 面向对象编程 第4章 Java 字符 […]


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/teach/8524.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】