Java——重载和重写

前言

在程序设计中常常会遇到对对方法的重载或者重写,下面将介绍重载和重写。html

重载(Overloade)

重载出现的缘由

任何程序设计语言都具有的一项重要特性就是对名字的运用。当建立一个对象时,就给对象的存储空间取了一个名字。方法名就是给某个动做取的名字。经过使用名字,咱们能够引用全部对象和方法。名字起的好可使程序更易于理解和修改。java

在大多数程序设计语言中要求为每一个方法提供惟一的标识符。不能使用print()的函数显示了整数以后,又用一个名为print()的函数显示浮点数。即,每一个函数(方法)都要有惟一的名称。这是迫使出现重载方法的理由之一。如果print()函数能够被重载了,那么就既能够输出整数也能够输出浮点数。或者又能够举例:咱们要计算两个整数相加,咱们能够设计方法为int add(int a, int b)。调用add(10,10)咱们就能够知道是计算两个整数相加。此时,咱们又想计算两个浮点数相加,由于add见名知意因此咱们继续使用这个名字,那么就须要方法double add(double a, double c)。因而,add()方法就被重载了。编程

在Java(和C++)里,构造器是强制重载方法出现的另外一个缘由。构造器的名字由类名决定,那么就只能有一个构造器。可是,又想使用多种方式建立对象又该怎么办呢?那么就只有重载构造器,使得同名不一样参的构造器同时存在。ide

重载的规则

方法重载是在一个类里面,方法名相同,而参数不一样,对返回值没有强制要求能够相同也能够不一样。方法重载须要注意一下几点:函数

  • 被重载的方法必须改变参数列表(参数个数或者类型不同)
  • 被重载的方法介意改变返回类型和访问修饰符
  • 被重载的方法能够声明新的或者更广的检查异常
  • 方法可以在同一个类中或者在一个子类中被重载
  • 不能够返回值类型做为分区重载函数的标准

区分重载方法

每一个重载的方法都有独一无二的参数类型列表。因此在区分重载方法时,只能以类名和方法的形参列表做为标准。this

那为何不能使用方法的返回值来区分呢?设计

好比下面两个方法,虽然它们有相同的名字和形式参数,可是却很容易区分它们3d

void f(){}
int f() {return 1;}

只要编译器能够根据语境明确判断出语义,好比在int x = f()中,那么的确能够根据此区分方法。不过,有时你并不关心方法的返回值,你想要的是方法调用的其余效果,这时你可能会调用方法而忽略返回值。因此,向下面这样的调用方法:code

f();

此时Java该怎样判断调用的是哪一个方法呢?别人也没法理解这个代码的含义。所以,依据方法的返回值来区分重载方法是行不通的。htm

重写(Override)

重写出现的缘由

先看一个例子

class Animal{
    public void printWhoIAm(){System.out.println("Animal")}
}
public class Dog extends Animal{
    public static void main(String args[]){
        Dog dog = new Dog();
        dog.printWhoIAm();
    }
} 
/*
output:
Animal
*/

当dog调用printWhoIAm()方法时,其实但愿的是输出“dog”,而不是Animal。要实现输出“Dog”,想到了重载,但是重载要求被重载的方法具备不一样的形参列表。这个方法不得行。dog调用的printWhoIAm()是父类中的,在子类中如果能够重写这个方法,那么就能够实现目的了。因而,重写(覆写)便产生了,为了解决父类方法在子类中不适用,而让子类重写方法的方式。咱们解决以上代码需求以下:

class Animal{
    public void printWhoIAm(){System.out.println("Animal")}
}
public class Dog extends Animal{
    //加上注解@Override能够强制进行重写的检查 防止本身重写错误
    @Override
    public void printWhoIAm(){System.out.println("Dog")}
    public static void main(String args[]){
        Dog dog = new Dog();
        dog.printWhoIAm();
    }
} 
/*
output:
Dog
*/

重写的规则

  • 重写是对父类容许访问的方法的实现过程进行从新编写,返回值不变或者为子类、形参列表不能改变而且访问控制权限不能严于父类。父类为default包访问权限,则子类就为public或者default;若父类是public,则子类必须为public。

  • 子类能够重写父类的除了构造器的任何方法。构造器是和类名相同的,不能被子类继承,所以也不能够被重写。

  • 重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,可是在重写这个方法的时候不能抛出 Exception 异常,由于 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。

子类能够重写父类中访问控制权限为private的方法吗?

答案是不能够。父类中的private方法对子类来讲是不可见的,就算子类中彻底按照重写要求定义方法,也不能算重写父类中的方法,实际上只是子类新增的一个方法。因此,只有非private方法才能够被重写。

super.方法()和this.方法()的区别

子类如果重写了父类的方法,那么父类原来的这个方法还能够被调用吗?答案是能够的,使用super对父类的方法进行调用。

class Animal{
    public void printWhoIAm(){System.out.println("Animal")}
}
public class Dog extends Animal{
    //加上注解@Override能够强制进行重写的检查 防止本身重写错误
    @Override
    public void printWhoIAm(){System.out.println("Dog")}
    public void print(){
        super.printWhoIAm();
        printWhoIAm();// this.printWhoIAm();
    }
    public static void main(String args[]){
        Dog dog = new Dog();
        dog.print();
    }
} 
/*
output:
Animal
Dog
*/

使用this.方法()会先在本类中查找是否存在要调用的方法,若是不存在则查找父类中是否具有此方法。若是有则调用,不然出现编译时错误。使用super.方法()会明确表示调用父类中的方法,直接去父类寻找要调用的方法。

重载和重写的区别

区别 重载 重写
参数列表 必须改 必定不能改
返回类型 能够修改 必定不能改
访问控制权限 能够修改 不能比父类严格
异常 能够修改 能够减小或删除,必定不能抛出新的或者更广的异常
发生范围 能够在一个类中也能够在子类中 在子类中

小结

须要注意的是重载和重写的定义形式。引用菜鸟教程的两句话和一张图结束。

  • 方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不一样或数量相同而类型和次序不一样,则称为方法的重载(Overloading)。

  • 方法重写是在子类存在方法与父类的方法的名字相同,并且参数的个数与类型同样,返回值也同样的方法,就称为重写(Overriding)

参考:
《Java编程思想》第四版
菜鸟教程http://www.runoob.com/java/java-override-overload.html