章
目
录
在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重写和重载概念区别进行的深入讲解。
文章目录前言 第1章 Java语言基础 第2章 流程控制语句 第3章 面向对象编程 第4章 Java 字符串 […]