java面向对象之多态
多态是Java面向对象的精华,在学习多态之前我们要先了解覆写(override)这个概念的使用方式和注意事项。
覆写(override)
class Person{
public void eat(){
System.out.println("People.eat");
}
}
class Man extends Person{
@override
public String eat(){};//报错,返回值发生改变
public void eat(String cake){}; //报错,不能有参数传入
}
当子类的方法签名和父类的方法签名完全相同时我们这时称子类对父类的方法进行了覆写。方法签名完全相同包括了方法的传入参数和返回值都必须是相同的。@overriide注解告诉我们这是一个覆写的方法,通过@override注解也可以检查语法错误,比如在返回值不同时就会报错。
什么是多态
接下来我们来看另一个例子,这个例子可以帮助我们理解多态是什么
class Main{
public static void main(String[] args){
Person p = new Man();
p.eat();
}
}
class Person{
public void eat(){
System.out.println("People.eat");
}
}
class Man extends Person{
@override
public void eat(){
System.out.println(man.eat);
}
}
在这里运行main()方法之后输出的结果是man.eat。可见我们的变量p的引用类型是Person但是最后调用的方法是实际类型的Man的eat()方法。因此我们可以说Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。这就是的多态。
多态的核心
正是因为多态的存在,当我们实例化一个对象时往往并不能知道这个对象执行的方法是哪一个类的方法。比如:
public void twiceEat(Person p){
p.eat();
p.eat();
}
这里我们并不能看到引用p的实际类型,所以无法知道执行的是哪一个类的方法,可能是Person也可能的Man。所以多态就是在运行期间动态的调用某个类的方法,引用执行的方法不由引用类型来决定。
运用多态
通过下面这个例子来看一下多态到底有什么用,这个例子中对普通收入,工资收入和国务院津贴都覆写了一个父类计算税费的方法。我们只需要利用循环条件遍历数组的方式就可以改变实际的变量类型,这样只需要一个方法就可以计算出三种收入的税费。
public class Main {
public static void main(String[] args) {
// 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
Income[] incomes = new Income[] {
new Income(3000),
new Salary(7500),
new StateCouncilSpecialAllowance(15000)
};
System.out.println(totalTax(incomes));
}
public static double totalTax(Income... incomes) {
double total = 0;
for (Income income: incomes) {
total = total + income.getTax();
}
return total;
}
}
class Income {
protected double income;
public Income(double income) {
this.income = income;
}
public double getTax() {
return income * 0.1; // 税率10%
}
}
class Salary extends Income {
public Salary(double income) {
super(income);
}
@Override
public double getTax() {
if (income <= 5000) {
return 0;
}
return (income - 5000) * 0.2;
}
}
class StateCouncilSpecialAllowance extends Income {
public StateCouncilSpecialAllowance(double income) {
super(income);
}
@Override
public double getTax() {
return 0;
}
}
如果我们需要新增加一种收入,只需要继续覆写getTax()方法,让主程序遍历这个新增加收入的实例就可以完成。可见多态功能的强大之处,它帮我们实现了引用动态的调用子类方法,不需要修改父类的代码。