返回顶部
扩大
缩小

Yeap

多态

在继承关系中,子类 如果定义了一个与父类方法签名完全相同的方法,被成为覆写(override)

例如:

class Person {
    public void run() { //方法
        System.out.println("Person.run");
    }
}

写一个子类,重写这个方法:

class Student extends Person {
    @Override
    public void run() {
        System.out.println("Student.run");
    }
}

Override和Overload不同的是,如果方法签名如果不同,就是Overload,Overload方法是一个新方法;如果方法签名相同,并且返回值也相同,就是Override

注意:方法名相同,方法参数相同,但方法返回值不同,也是不同的方法。在Java程序中,出现这种情况,编译器会报错。

Person person = new student();//父类的引用指向子类的对象

如果子类重写了父类的方法:

public class Main {
    public static void main(String[] args) {
        Person p = new Student();
        p.run(); // 应该打印Person.run还是Student.run?
    }
}

class Person {
    public void run() {
        System.out.println("Person.run");
    }
}

class Student extends Person {
    @Override
    public void run() {
        System.out.println("Student.run");
    }
}

运行发现:这里调用的方法是Student的run()方法。

可以得到:Java的实例方法调用基于运行时的实际类型的动态调用,而非变量的声明类型。这个特性在面向对象编程中称之为多态。

多态

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

Person p = new Student();
p.run(); // 无法确定运行时究竟调用哪个run()方法

调用的是Studentrun()方法!

但是,这样的话:

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

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

所以、多态的特征就是,运行才能动态决定调用的方法。对某个类型调用某个方法,执行的实际方法可能就是某个子类的覆写方法。这种不确定的方法调用的作用是啥呢?

class Income { //一个收入类
    protected double income;
    public double getTax() {
        return income * 0.1; // 税率10%
    }
}

对于工资收入,可以减去一个基数,那么我们可以从Income派生出SalaryIncome,并覆写getTax()

lass Salary extends Income {
    @Override
    public double getTax() {//重写这个方父类的方法
        if (income <= 5000) {
            return 0;
        }
        return (income - 5000) * 0.2;
    }
}
class StateCouncilSpecialAllowance extends Income {
    @Override
    public double getTax() {//再来一个重写
        return 0;
    }
}
public double totalTax(Income... incomes) {
    double total = 0;
    for (Income income: incomes) {
        total = total + income.getTax();
    }
    return total;
}

总的代码:

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)); //300+500
    }

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

class Income {
    protected double income; //3000   7500  15000

    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;
    }
}

调用super

在子类的覆写方法中,如果要调用父类的被覆写的方法,可以通过super关键字类调用。

class Person {
    protected String name;
    public String hello() {
        return "Hello, " + name;
    }
}

Student extends Person {
    @Override
    public String hello() {
        // 调用父类的hello()方法:
        return super.hello() + "!";
    }
}

final

继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标识为 final。用final修饰的方法可以被继承,但是不能被重写。

class Person {
    protected String name;
    public final String hello() {
        return "Hello, " + name;
    }
}

Student extends Person {
    // compile error: 不允许覆写
    @Override
    public String hello() {
    }
}

如果一个类不希望任何类继承它,那么可以把这个类标记为 final。用final修饰的类不能被继承:

final class Person {
    protected String name;
}

// compile error: 不允许继承自Person
Student extends Person {
}

对一个类的实例字段。同样可以用final修饰,用final修饰的字段在初始化后不能被修改。

class Person {
    public final String name = "Unamed";
}
Person p = new Person();
p.name = "New Name"; // compile error!

可以在构造方法中初始化final字段:

class Person {
    public final String name;
    public Person(String name) {
        this.name = name;
    }
}

这种方法更为常用,因为可以保证实例一旦创建,其final字段就不可修改。

posted on 2020-11-23 22:32  YP泡泡  阅读(84)  评论(0)    收藏  举报

导航