面试题:重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
答:方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。
Overload(重载)
(1) 重载Overload是一个类中多态性的一种表现。是编译时的多态性。方法重载是让类以统一的方式处理不同类型数据的一种手段。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载。
(2) Java的方法重载,就是在类中可以创建多个方法,它们具有相同的名字,但具有不同的参数列表。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这就是多态性。
(3) 重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准。
(4) 不能通过访问权限、返回类型、抛出的异常进行重载;
(5) 方法的异常类型和数目不会对重载造成影响;
Override(重写、覆盖)
(1) 父类与子类之间的多态性,对父类的函数进行重新定义。是运行时的多样性。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Override)。在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
(2)若子类中的方法与父类中的某一方法具有相同的方法名、参数列表和兼容的返回类型,则新方法将覆盖原有的方法。如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
(3)子类函数的访问修饰权限不能少于父类的。
普通的方法继承:
class Parent {
public Parent make(int i) {
System.out.println("Parent int: "+i);
return null;
}
}
class Child extends Parent{
}
public class OverrideTest {
public static void main(String []args){
Parent p = new Parent();
Child c = new Child();
p.make(1); //Parent int: 1
p.make(new Integer(1)); //Parent int: 1
c.make(1); //Parent int: 1
c.make(new Integer(1)); //Parent int: 1
}
}
普通的重载,参数列表相同,返回值相同
class Parent {
public Parent make(int i) {
System.out.println("Parent int: "+i);
return null;
}
}
class Child extends Parent{
@Override
public Parent make(int i) {
System.out.println("Child int: "+i);
return null;
}
}
public class OverrideTest {
public static void main(String []args){
Parent p = new Parent();
Child c = new Child();
p.make(1); //Parent int: 1
p.make(new Integer(1)); //Parent int: 1
c.make(1); //Child int: 1
c.make(new Integer(1)); //Child int: 1
}
}
重载,但是子类的返回类型是父类被重写方法的子类,即重写返回方法兼容,编译通过。
class Parent {
public Parent make(int i) {
System.out.println("Parent int: "+i);
return null;
}
}
class Child extends Parent{
@Override
public Child make(int i) {
System.out.println("Child int: "+i);
return null;
}
}
public class OverrideTest {
public static void main(String []args){
Parent p = new Parent();
Child c = new Child();
p.make(1); //Parent int: 1
p.make(new Integer(1)); //Parent int: 1
c.make(1); //Child int: 1
c.make(new Integer(1)); //Child int: 1
}
}
突然想到一道int和Integer的面试题,Integer的自动拆箱与装箱,不知道如果把Child的方法参数由int改成Integer会如何,发现编译出错,可见参数列表需要完全相同。
class Parent {
public Parent make(int i) {
System.out.println("Parent int: "+i);
return null;
}
}
class Child extends Parent{
@Override
public Child make(Integer i) { //编译出错
System.out.println("Child Integer: "+i);
return null;
}
}
不重写make(int)方法,另写一个make(Integer)方法(此处应该算重载了,继承了父类的make(int)方法,而make(Integer)参数列表不同):
class Parent {
public Parent make(int i) {
System.out.println("Parent int: "+i);
return null;
}
}
class Child extends Parent{
public Child make(Integer i) {
System.out.println("Child Integer: "+i);
return null;
}
}
public class OverrideTest {
public static void main(String []args){
Parent p = new Parent();
Child c = new Child();
p.make(1); //Parent int: 1
p.make(new Integer(1)); //Parent int: 1
c.make(1); //Parent int: 1
c.make(new Integer(1)); //Child Integer: 1
}
}
此时c.make(new Integer(1))则调用Child.make(Integer)方法,不会拆包并调用父类Father.make(int)方法。
重写make(int)方法,并编写make(Integer)方法:
class Parent {
public Parent make(int i) {
System.out.println("Parent int: "+i);
return null;
}
}
class Child extends Parent{
@Override
public Parent make(int i) {
System.out.println("Child int: "+i);
return null;
}
public Child make(Integer i) {
System.out.println("Child Integer: "+i);
return null;
}
}
public class OverrideTest {
public static void main(String []args){
Parent p = new Parent();
Child c = new Child();
p.make(1); //Parent int: 1
p.make(new Integer(1)); //Parent int: 1
c.make(1); //Child int: 1
c.make(new Integer(1)); //Child Integer: 1
}
}
此处Child.make(Integer)和Child.make(int)重载,上面是Child继承自Father的make(int)和Child自己的make(int)重载。
总结:
重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。
3、重写的方法的返回值必须和被重写的方法的返回一致或者兼容;
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写;
6、静态方法不能被重写为非静态的方法(会编译出错);
7、父类方法被final时,无论该方法被public、protected及默认所修饰,子类均不能重写该方法。
overload是重载,一般是用于在一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同。
重载的规则:
1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响。
联系与区别
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。