JavaTutorial

[TOC]

上节课的总结:

继承

异常:

多态

上节课我们讲到了Java类的继承,子类可以继承父类。

那么,可以将子类看作特殊的父类

Java种可以将子类对象直接赋值给父类的一个变量,系统会自动完成类型转换,称之为上转型

//这里Student时Person的子类
Person p = new Student();

了解了这个概念之后,接下来我们要讲解多态。

什么是多态?

多态是面向对象编程的三大特征之一。

多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时实际类型的方法,例如:

public void runTwice(Person p) {
    p.run();
    p.run();
}

它传入的参数类型是Person,但是子类是特殊的父类

我们无法知道传入的参数实际类型究竟是还是Student,还是Person的其他子类,因此,也无法确定调用的是不是Person类定义的run()方法。

运行期才能动态决定调用的子类方法就是多态的特性。

这种不确定性的方法调用,究竟有什么作用呢?

多态的作用

举一个例子:

每个公民都是纳税人,我们需要写一个程序统计纳税人应该纳多少税。

假设我们定义一种普通收入,需要给它报税,那么先定义一个Income类:

(这个类是所有收入的父类,也成为基类)

class Income {
    public double income;
    public double getTax() {
        return income * 0.1;
    }
}

对于工资收入,咱们国家是要求工资低于个税起征点的部分不用交个人所得税,目前这个数是5000。工资高于5000的,可以减去5000再收税。讲义中忽略了专项扣除和预扣预缴税额,假设税率为20%。

那么我们可以从Income派生出SalaryIncome,并覆盖getTax()方法。

(继承和派生是不同的说法)

class Salary extends Income {
    @override
    public double getTax() {
        if(income <= 5000) {
            return 0;
        }
        return (income - 5000) * 0.2;
    }
}

假如你是高层次技术人员和高技能人才,那么你可能享受国务院特殊津贴,发给你的奖金你就不需要交税了

class SpecialAllowance extends {
    @Override
    public double getTax() {
        return 0;
    }
}

现在,我们要编写一个报税的财务软件,对于一个人的所有收入进行报税,可以这么写:

注意,这里参数的写法Type...,表示可以传入的参数个数不确定。

public double totalTax(Income... incomes) {
    double total = 0;
    for(Income income : income) {
        total  = total + income.getTax();
    }
}

然后整合下来的程序就是这样:

public class Solution {
    public static void main(String args[]) {
      //给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
      Income[] incomes = new Income[] {
          new Income(300),
          new Salary(7500),
          new SpecialAllowance(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 SpecialAllowance extends Income {
    public SpecialAllowance(double income) {
        super(income);
    }

    @Override
    public double getTax() {
        return 0;
    }
}

观察totalTax()方法:利用多态,totalTax()方法只需要和Income打交道,它完全不需要知道Salary和SpecialAllowance的存在,就可以正确计算出总的税收

如果我们要新增一种稿费收入,只需要从Income派生,然后正确覆写getTax()方法就可以。把新的类型传入totalTax(),不需要修改任何代码

多态具有一个非常强大的功能,就是允许添加更多类型的子类实现功能拓展,却不需要修改基于父类的代码

表驱动编程法