方法重载(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方法可以被重写。