方法重载(Method Overloading)
方法重载指的是在一个类中,声明了多个名称相同而参数列表不同的方法(包括构造函数)。每个重载的方法都必须有一个独一无二的参数列表。
方法重载的规则如下:
- 重载的方法必须具有不同的参数列表
- 重载的方法可以有不同的返回值类型
- 重载的方法可以有不同的访问修饰符
代码清单-1:
/**
* 重载方法示例
*
* author jackie
*/
public class OverloadingIllusion {
// 使用返回值类型无法区分重载方法
public int overloadingTest() {
return 1;
}
/*public String overloadingTest() {
return "OverloadingTest";
}*/
public void overloadingTest(int a) {
System.out.println("OverloadingTest" + a);
}
// 下面两个重载方法参数列表顺序不一致,但也都是重载方法。而且方法的修饰符可以不一样
public String overloadingTest(int a, String s) {
return s + a;
}
private String overloadingTest(String s, int a) {
return s + a;
}
public float overloadingTest(float a, float b) {
return a + b;
}
public long overloadingTest(long a, int b) {
return a + b;
}
public static void main(String[] args) {
OverloadingIllusion o = new OverloadingIllusion();
System.out.println("OverloadingTest" + o.overloadingTest());
o.overloadingTest(2);
System.out.println(o.overloadingTest(3, "OverloadingTest"));
System.out.println(o.overloadingTest("OverloadingTest", 4));
// 如果传入方法的实际参数类型小于方法声明中的形式参数类型,实际参数的类型会被提升
System.out.println(o.overloadingTest(1, 4));
// 如果传入方法的实际参数类型大于方法声明中的形式参数类型,则必须要通过强制类型转换将实际参数的类型窄化,否则编译器会报错
System.out.println(o.overloadingTest((float)1.0d, (float)2.0d));
}
}
输出结果如下:
OverloadingTest1
OverloadingTest2
OverloadingTest3
OverloadingTest4
5
3.0
方法重写(Method Overriding)
在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写,方法重写又称方法覆盖。 若子类中声明的方法与父类中的某一方法具有相同的方法名、返回值类型和参数列表,则子类中的方法将覆盖父类中的方法。 如需要调用父类中原有的方法,可以使用super关键字,该关键字引用了当前类的父类。
方法重写的规则如下:
- 重写方法的参数列表必须与被重写方法的参数列表完全相同;
- 重写方法的返回值类型必须与被重写方法的返回值类型完全相同;
- 重写方法的访问权限不能比被重写方法的访问权限更严格。比如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
- 父类的成员方法只能被它的子类重写。
- 声明为final的方法不能被重写。
- 声明为static的方法不能被重写,但是能够在子类中再次声明,子类中的static方法会被隐藏。
- 如果一个方法不能被继承,那么该方法不能被重写。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
代码清单-2
/**
* 重写示例
*
* author jackie
*
*/
public class OverridingIllusion extends OverridingTest {
// 重写方法的访问权限不能比被重写方法的访问权限更严格,否则编译器会报错
/*protected void print() {
System.out.println("print() in subclass OverridingIllusion");
}*/
public void print() {
// 可以使用super关键字调用父类的方法
super.print();
System.out.println("print() in subclass OverridingIllusion");
}
// 实例方法不能重写父类的静态方法,否则编译器会报错
/*public void m() {
System.out.println("OverridingIllusion.m()");
}*/
// 重写方法不能抛出比父类方法声明的异常级别更高的异常
/*public void e() throws Exception {
System.out.println("OverridingIllusion.e()");
}*/
public static void m() {
System.out.println("OverridingIllusion.m()");
}
public static void main(String[] args) {
OverridingIllusion oi = new OverridingIllusion();
oi.print();
// static、final和private方法不能被重写
//oi.f();
//oi.g();
oi.m();
// OverridingIllusion对象向上转型为OverridingTest类的对象,但仍然调用的是OverridingIllusion中的print()方法
OverridingTest ot = oi;
ot.print();
m();
// OverridingIllusion对象向上转型为OverridingTest类的对象,调用的方法却是OverridingTest类中的print()方法
// 子类的static方法被隐藏
ot.m();
}
}
class OverridingTest {
public void print() {
System.out.println("print() in base class OverridingTest");
}
public void e() throws IOException {
System.out.println("OverridingTest.e()");
}
// private方法显示地声明为final
private final void f() {
System.out.println("OverridingTest.f()");
}
// private方法隐式地声明为final
private void g() {
System.out.println("OverridingTest.g()");
}
public static void m() {
System.out.println("OverridingTest.m()");
}
}
输出结果如下:
print() in base class OverridingTest
print() in subclass OverridingIllusion
OverridingIllusion.m()
print() in base class OverridingTest
print() in subclass OverridingIllusion
OverridingIllusion.m()
OverridingTest.m()
方法重写与方法重载的区别
区别点 | 方法重载 | 方法重写 |
---|---|---|
参数列表 | 必须完全不同 | 必须相同 |
返回值类型 | 可以不同 | 必须相同 |
方法声明的异常 | 可以不同 | 可以减少或删除,一定不能抛出新的或者层次更高的异常 |
访问控制 | 可以不同 | 一定不能做更严格的限制(可以降低限制) |
最佳实践
1、虽然参数的顺序不同也能够区分重载方法,但最好别这样做,因为会造成代码难以维护;2、对于父类的private方法,子类中最好不要声明同名的方法,因为会让人误解private方法可以被重写。