• 多态(基本介绍、快速入门、注意事项以及细节、动态绑定机制)


    目录

    1.一个问题引出多态

    2.多态的基本介绍

    3.对象的多态

    4.多态快速入门案例

    5.多态注意事项和细节问题(向上转型和向下转型)

    6.属性重写问题

    7.instanceOf比较操作符

    8.练习题

    9.java的动态绑定机制(非常非常重要)

    10.多态数组

    11.多态参数


    1.一个问题引出多态

    1. public class Food {
    2. private String name;
    3. public Food(String name) {
    4. this.name = name;
    5. }
    6. public String getName() {
    7. return name;
    8. }
    9. public void setName(String name) {
    10. this.name = name;
    11. }
    12. }
    1. public class Fish extends Food{
    2. public Fish(String name) {
    3. super(name);
    4. }
    5. }
    1. public class Bone extends Food{
    2. public Bone(String name) {
    3. super(name);
    4. }
    5. }
    1. public class Animal {
    2. private String name;
    3. public Animal(String name) {
    4. this.name = name;
    5. }
    6. public String getName() {
    7. return name;
    8. }
    9. public void setName(String name) {
    10. this.name = name;
    11. }
    12. }
    1. public class Cat extends Animal {
    2. public Cat(String name) {
    3. super(name);
    4. }
    5. }
    1. public class Dog extends Animal{
    2. public Dog(String name) {
    3. super(name);
    4. }
    5. }

    这些类写好了之后,再单写一个Master类  

    1. public class Master{
    2. private String name; //主人名称
    3. public Master(String name) {
    4. this.name = name;
    5. }
    6. public String getName() {
    7. return name;
    8. }
    9. public void setName(String name) {
    10. this.name = name;
    11. }
    12. public void feed(Dog dog,Bone bone){
    13. System.out.println("主人 "+name+" 给 "+ dog.getName()+" 吃"+bone.getName());
    14. }
    15. }

    然后进行测试

    1. public class Poly01 {
    2. public static void main(String[] args) {
    3. Master tom = new Master("汤姆");
    4. Dog dog = new Dog("大黄");
    5. Bone bone = new Bone("大棒骨");
    6. tom.feed(dog,bone);
    7. }
    8. }

                                   


    那么我们现在又要让主人给小猫喂鱼,又要在Master类里写一个feed的方法,只是参数不一样,也就是重载。  

    1. //主人给小狗 喂食 黄花鱼
    2. public void feed(Cat cat,Fish fish){
    3. System.out.println("主人 "+name+" 给 "+ cat.getName()+" 吃"+fish.getName());
    4. }

    测试

    1. public class Poly01 {
    2. public static void main(String[] args) {
    3. Master tom = new Master("汤姆");
    4. Dog dog = new Dog("大黄");
    5. Bone bone = new Bone("大棒骨");
    6. tom.feed(dog,bone);
    7. Cat cat = new Cat("小花猫");
    8. Fish fish = new Fish("黄花鱼");
    9. System.out.println("==========");
    10. tom.feed(cat,fish);
    11. }
    12. }

    注:

    从功能实现上来说,效果确实是出来了,但是我们这样写下去会出现一种后果

    如果随着代码的扩展,将来主人可能还会养猪、兔子、鸟、等各种动物,这样的话不同的动物吃的东西也不一样,猪喜欢吃米饭,鱼喜欢吃虫子,

    这样动物很多,食物也很多,就会造成feed方法扩展越来越多,不利于管理和维护。

    这里就引出多态


    2.多态的基本介绍

    方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

    1. public class PloyMethod {
    2. public static void main(String[] args) {
    3. }
    4. }
    5. class B { //父类
    6. public void say() {
    7. System.out.println("B say() 方法被调用...");
    8. }
    9. }
    10. class A extends B { //子类
    11. public int sum(int n1, int n2) { //和下面的sum 构成重载
    12. return n1 + n2;
    13. }
    14. public int sum(int n1, int n2, int n3) {
    15. return n1 + n2 + n3;
    16. }
    17. public void say(){
    18. System.out.println("A say()方法被调用...");
    19. }
    20. }

    这里有父类和子类,子类里有2个sum构成重载,那么这是如何构成多态的呢?

    此时我们在main方法里这样写:

    1. public static void main(String[] args) {
    2. // 方法重载体现多态
    3. A a = new A();
    4. // 这里我们传入不同的参数,就会调用不同的sum方法,就体现出多态
    5. System.out.println(a.sum(10,20));
    6. System.out.println(a.sum(10,20,30));
    7. }

    我们通过不同的参数个数去调用sum方法,就会去调用不同的方法,因此对sum方法来说,就是多种状态的体现。  


    重载体现出了多态,那么方法的重写又是如何体现出多态?

    同样是刚刚的例子,我们可以看到父类由一个say方法,子类也有一个say方法

    这里我们在main方法中new一个B对象,调用a的say方法和b的say方法。

    1. //方法重写体现多态
    2. B b = new B();
    3. a.say();
    4. b.say();

                                                      

    这里也会体现出多态。

    注:

    重载和重写体现的多态是比较好理解的,真正难理解的是对象的多态,因为对象多态里面很复杂,对象里面会有编译类型和运行类型的概念。  


    3.对象的多态

    (1)一个对象的编译类型和运行类型可以不一致

    这里Dog类是Animal的子类,这里可以把一个子类对象赋给一个父类的对象引用,也就是说我能用一个父类的引用指向子类对象,现在这个animal准确的讲是对象的引用,并不是对象,而是对象的引用,而后面new的才是真正的对象,此时animal的编译类型是Animal,运行类型是Dog

    (2)编译类型在定义对象时,就确定了,不能改变  

    Animal animal = new Dog();

    我们可以看到以上代码,它一但定义好了,也就是animal,它的编译类型就是Animal,不可以改变,已经确定下来了

    (3)运行类型是可以改变的

    animal = new Cat();

    这个时候animal的运行类型变成了Cat,编译类型仍然是Animal

    (4)编译类型看定义时 = 号的左边,运行类型看 = 号的右边


    代码演示

    1. public class Animal {
    2. public void cry(){
    3. System.out.println("Animal 动物在叫...");
    4. }
    5. }
    1. public class Cat extends Animal{
    2. public void cry() {
    3. System.out.println("Cat cry() 小猫喵喵叫...");
    4. }
    5. }
    1. public class Dog extends Animal{
    2. public void cry() {
    3. System.out.println("Dog cry() 小狗汪汪叫...");
    4. }
    5. }
    1. public class PolyObject {
    2. public static void main(String[] args) {
    3. //体验对象多态的特点
    4. //animal 编译类型已经确定 --> Animal,运行类型是 Dog
    5. Animal animal = new Dog();
    6. //因为运行时,也就是执行到animal.cry()这一行代码的时候,animal的运行类型是Dog,因此这个cry就会找运行类型的cry,也就是dog里的cry
    7. animal.cry(); //小狗汪汪叫
    8. }
    9. }

    运行时,也就是执行到animal.cry()这一行代码的时候,animal的运行类型是Dog,因此这个cry就会找运行类型的cry,也就是dog里的cry


    此时我们再把运行类型改成Cat

    1. animal = new Cat();
    2. animal.cry(); //小猫喵喵叫

    编译类型在定义的时候就已经确定了,这是无法改变的,一直是animal,但是运行类型是Cat。

    一但我们将右边new为Cat的时候,animal的指向就发生变化了,这时候是指向Cat,也就是说,在运行的时候主要看的是堆里面的,既然运行类型变成猫了,那么在执行执行的时候又以猫为主,运行的时候全部看的是堆里面的真正对象。

    4.多态快速入门案例

    回顾我们一开始多态问题的引出,此时我们来分析一下,这确实要写很多个feed方法

    1. //主人给小狗 喂食 骨头
    2. public void feed(Dog dog,Bone bone){
    3. System.out.println("主人 "+name+" 给 "+ dog.getName()+" 吃"+bone.getName());
    4. }
    5. //主人给小狗 喂食 黄花鱼
    6. public void feed(Cat cat,Fish fish){
    7. System.out.println("主人 "+name+" 给 "+ cat.getName()+" 吃"+fish.getName());
    8. }

    我们可以对代码进行简化

    1. //使用多态机制,可以统一的管理主人喂食的问题
    2. public void feed(Animal animal,Food food){
    3. System.out.println("主人 "+name+" 给 "+ animal.getName()+" 吃"+food.getName());
    4. }

    里面的参数类型可以用父类来接收,父类的引用可以指向它的子类,所以里面直接写个Animal就好了,同样食物也是。

    由于animal的编译类型是Animal类型,它可以指向(接收) Animal子类的对象。

    同样的道理,Food的编译类型是food,它可以指向(接收)Food的子类对象

    这时候去测试:

    1. public class Poly01 {
    2. public static void main(String[] args) {
    3. Master tom = new Master("汤姆");
    4. Dog dog = new Dog("大黄");
    5. Bone bone = new Bone("大棒骨");
    6. tom.feed(dog,bone);
    7. Cat cat = new Cat("小花猫");
    8. Fish fish = new Fish("黄花鱼");
    9. System.out.println("==========");
    10. tom.feed(cat,fish);
    11. }
    12. }

                                

    多态带来的好处不止这个。

    假如我们此时让主人喂食给一只猪,我们来编写一下代码

    1. public class Pig extends Animal{
    2. public Pig(String name) {
    3. super(name);
    4. }
    5. }
    1. public class Rice extends Food{
    2. public Rice(String name) {
    3. super(name);
    4. }
    5. }

    此时主人要给小猪喂食物,我们会发现,这个feed方法不用动,因为它已经可以接收所有动物的子类对象,也可以接收所有食物的子类对象  

    1. //使用多态机制,可以统一的管理主人喂食的问题
    2. public void feed(Animal animal,Food food){
    3. System.out.println("主人 "+name+" 给 "+ animal.getName()+" 吃"+food.getName());
    4. }

    直接测试:

    1. public class Poly01 {
    2. public static void main(String[] args) {
    3. Master tom = new Master("汤姆");
    4. //添加给小猪喂米饭
    5. Pig pig = new Pig("小花猪");
    6. Rice rice = new Rice("米饭");
    7. tom.feed(pig,rice);
    8. }
    9. }

                                    


    5.多态注意事项和细节问题(向上转型和向下转型)

    多态的前提是:两个对象(类)存在继承关系

    多态的向上转型:

    那么为了举例子,我们重新建一个Animal类和Cat类

    1. public class Animal {
    2. String name = "动物";
    3. int age=10;
    4. public void sleep(){
    5. System.out.println("睡");
    6. }
    7. public void run(){
    8. System.out.println("跑");
    9. }
    10. public void eat(){
    11. System.out.println("吃");
    12. }
    13. public void show(){
    14. System.out.println("hello,你好");
    15. }
    16. }
    1. public class Cat extends Animal{
    2. public void eat(){ //方法重写
    3. System.out.println("猫吃鱼");
    4. }
    5. public void catchMouse(){ //Cat特有的方法
    6. System.out.println("猫抓老鼠");
    7. }
    8. }
    1. public class PolyDetail {
    2. public static void main(String[] args) {
    3. //(向上转型):父类的引用指向子类的对象
    4. //语法:父类类型引用名 = new 子类类型();
    5. Animal animal = new Cat();
    6. Object object = new Cat();
    7. System.out.println("OK");
    8. }
    9. }

    将Animal和Object作为引用指向子类的对象这样都是可以的,虽然Object不是Cat的直接父类,但是是Animal的父类。

                                


    可以调用父类中的所有成员(需遵守访问权限)

    但是就是不能调用子类中的catchMouse()方法,如果需要调用的话,则需要强转

    也就是说不能调用子类的特有成员,这个例子里catchMouse()是Cat类独有的方法,在编译阶段,能调用哪些成员,是由编译类型来决定的。

    此时我们调用4个方法:

    1. public class PolyDetail {
    2. public static void main(String[] args) {
    3. //(向上转型):父类的引用指向子类的对象
    4. //语法:父类类型引用名 = new 子类类型();
    5. Animal animal = new Cat();
    6. animal.eat();
    7. animal.run();
    8. animal.show();
    9. animal.sleep();
    10. }
    11. }

    那么这样的输出结果会是什么呢?? 

    这里我们要清楚,在编译阶段,它指定编译类型,也就是javac,但是一但运行起来以后,其实运行的时候就是交给java虚拟机来做了,它在运行程序的时候,不管你编译类型,只看你运行类型,而当我们执行animal.eat()这一行的时候,会先去Cat类里面找eat方法,如果有的话直接找Cat里的eat方法,那么这里直接输出"猫吃鱼"。

    注:

    调用方法的时候,按照从子类(运行类型)开始查找方法,然后调用,规则和前面的方法调用规则一致


    向下转型:

    1. public class PolyDetail {
    2. public static void main(String[] args) {
    3. //(向上转型):父类的引用指向子类的对象
    4. //语法:父类类型引用名 = new 子类类型();
    5. Animal animal = new Cat();
    6. animal.eat();
    7. animal.run();
    8. animal.show();
    9. animal.sleep();
    10. }
    11. }

    向上转型的调用方法规则中有:可以调用父类中的所有成员,但是不能调用子类的特有成员。  


    那么我们就是想调用子类的特有成员该怎么做呢?

    这里就出现了多态的向下转型

    1. //多态的向下转型
    2. //语法:子类类型 引用名 = (子类类型) 父类引用.
    3. Cat cat = (Cat)animal;
    4. cat.catchMouse();

    这个时候catchMouse(),就可以调用了,此时cat的编译类型是Cat,运行类型还是Cat,因为强转为Cat了


    那么此时我们再来看一段代码,我们写了一个Dog类,让Dog类也去继承这个Animal

    Dog dog = (Dog)animal;

    一开始的Cat cat = (Cat)animal这段代码中的animal是因为指向的是Cat对象,那么强转为Cat,这时又有一个cat也是指向到Cat对象。

    但是我们想强转为Dog,我们这么想一想,animal指向的是Cat对象,总不可能让一个狗指向猫吧?

                      

    6.属性重写问题

    属性没有重写之说,属性的值看编译类型。

    1. public class PolyDetail2 {
    2. public static void main(String[] args) {
    3. Base base = new Sub();
    4. System.out.println(base.count); //10
    5. Sub sub = new Sub();
    6. System.out.println(sub.count); //20
    7. }
    8. }
    9. class Base{ //父类
    10. int count=10; //属性
    11. }
    12. class Sub extends Base{ //子类
    13. int count=20; //属性
    14. }

    7.instanceOf比较操作符

    instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型

    1. public class PolyDetail3 {
    2. public static void main(String[] args) {
    3. BB bb = new BB(); //true
    4. System.out.println(bb instanceof BB); //true
    5. }
    6. }
    7. class AA{} //父类
    8. class BB extends AA{} //子类

    那么instanceOf判断的是编译类型还是判断的运行类型?

    1. //aa 编译类型是 AA,运行类型是BB
    2. AA aa = new BB();
    3. System.out.println(aa instanceof AA); //true
    4. System.out.println(aa instanceof BB); //true

    那么得出结论:判断对象的运行类型是否为 XX 类型或 XX 类型的子类型


    8.练习题


    9.java的动态绑定机制(非常非常重要)

    Java 重要特性: 动态绑定机制

    我们先来看个问题:

    1. public class DynamicBinding {
    2. public static void main(String[] args) {
    3. A a = new B();
    4. System.out.println(a.sum()); //40
    5. System.out.println(a.sum1()); //30
    6. }
    7. }
    8. class A {
    9. public int i = 10;
    10. public int sum() {
    11. return getI() + 10;
    12. }
    13. public int sum1() {
    14. return i + 10;
    15. }
    16. public int getI() {
    17. return i;
    18. }
    19. }
    20. class B extends A {
    21. public int i = 20;
    22. public int sum() {
    23. return i + 20;
    24. }
    25. public int getI() {
    26. return i;
    27. }
    28. public int sum1() {
    29. return i + 10;
    30. }
    31. }

    这里毫无疑问,输出40和30


    但是我们此时,将子类的sum方法注释掉

    此时由于子类没有sum()方法,则去找父类的,但是父类里面又有一个getI()方法,此时子类和父类都有这个getI()方法,那么调用的到底是父类的getI还是子类的?这里就会出现一个动态绑定机制在里面了。  

    以上面的例子为例,a.sum()这一步,执行到父类的sum()方法时,我们会发现:

    由于a.sum()中的a是运行类型是B,此时去调用子类的getI()

    而到了子类的getI()的时候,里面的return i;i是个属性,那么此时这个i就是子类里的i,也就是20;所以在父类里的sum方法,return的getI()就是20+10

    而最后的运行结果则是从40变为30。


    那么现在我们继续把子类的sum1()注释掉 

    这里调用方法,同样跟该对象的内存地址绑定,但是B类的sum1被我们注释掉,这里就是没有,但是这里继承机制发生了,去父类去找,父类由sum1方法,此时return i+10;属性是没有动态绑定机制的,也就是哪里声明哪里使用,这个i就是当前类,也就是10,那么最后输出20。


    10.多态数组

    1. public class Person {
    2. private String name;
    3. private int age;
    4. public Person(String name, int age) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. public String getName() {
    9. return name;
    10. }
    11. public void setName(String name) {
    12. this.name = name;
    13. }
    14. public int getAge() {
    15. return age;
    16. }
    17. public void setAge(int age) {
    18. this.age = age;
    19. }
    20. public String say(){
    21. return name + "\t" + age;
    22. }
    23. }
    1. public class Student extends Person{
    2. private double score;
    3. public Student(String name, int age, double score) {
    4. super(name, age);
    5. this.score = score;
    6. }
    7. public double getScore() {
    8. return score;
    9. }
    10. public void setScore(double score) {
    11. this.score = score;
    12. }
    13. //重写父类say
    14. @Override
    15. public String say() {
    16. return super.say() + " score="+score;
    17. }
    18. }
    1. public class Teacher extends Person{
    2. private double salary;
    3. public Teacher(String name, int age, double salary) {
    4. super(name, age);
    5. this.salary = salary;
    6. }
    7. public double getSalary() {
    8. return salary;
    9. }
    10. public void setSalary(double salary) {
    11. this.salary = salary;
    12. }
    13. //重写父类say方法
    14. @Override
    15. public String say() {
    16. return super.say() + " salary="+salary;
    17. }
    18. }
    1. public class PloyArray {
    2. public static void main(String[] args) {
    3. /**
    4. * 应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象
    5. * 2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象 say 方法
    6. */
    7. Person[] persons = new Person[5];
    8. persons[0] = new Person("jack",20);
    9. persons[1] = new Student("jack",18,100);
    10. persons[2] = new Student("smith",19,30.1);
    11. persons[3] = new Teacher("scott",30,20000);
    12. persons[4] = new Teacher("king",50,25000);
    13. //循环遍历多态数组,调用say方法
    14. for (int i = 0; i < persons.length; i++) {
    15. //person[i]的编译类型是Person,运行类型是根据实际情况由JVM来判断
    16. System.out.println(persons[i].say());//动态绑定机制
    17. }
    18. }
    19. }

    既然要统一放在一个数组里,肯定得用父类类型来接收,因为父类的引用可以指向子类的对象,所以可以这样创建对象数组:Person[] persons = new Person[5];那这里面可以放Person和Person的子类,最后循环遍历,就会跟着运行类型进行输入say方法


    此时我们对这个问题进行强化一下:

    那么我们添加一下方法

    1. //学生特有方法
    2. public void sutdy(){
    3. System.out.println("学生 "+getName()+" 正在学java课程");
    4. }
    1. //老师特有方法
    2. public void teach(){
    3. System.out.println("老师 "+getName()+" 正在讲java课程");
    4. }

    但是我们在循环里面调用,是没办法去调用的

    因为person[i]的编译类型是Person类,而Person类是没有这个方法的,那么我们可以在循环里面进行判断,判断运行类型是不是学生,instanceof判断运行类型是不是Student,或者是Student的子类。

    1. public class PloyArray {
    2. public static void main(String[] args) {
    3. /**
    4. * 应用实例:现有一个继承结构如下:要求创建 1 个 Person 对象
    5. * 2 个 Student 对象和 2 个 Teacher 对象, 统一放在数组中,并调用每个对象 say 方法
    6. */
    7. Person[] persons = new Person[5];
    8. persons[0] = new Person("jack", 20);
    9. persons[1] = new Student("mary", 18, 100);
    10. persons[2] = new Student("smith", 19, 30.1);
    11. persons[3] = new Teacher("scott", 30, 20000);
    12. persons[4] = new Teacher("king", 50, 25000);
    13. //循环遍历多态数组,调用say方法
    14. for (int i = 0; i < persons.length; i++) {
    15. //person[i]的编译类型是Person,运行类型是根据实际情况由JVM来判断
    16. System.out.println(persons[i].say());//动态绑定机制
    17. if (persons[i] instanceof Student) { //判断person[i]的运行类型是不是Student
    18. Student student = (Student) persons[i]; //向下转型
    19. student.study();
    20. //这里可以使用一条语句写:((Student)person[i]).study();
    21. } else if (persons[i] instanceof Teacher) {
    22. ((Teacher) persons[i]).teach();
    23. } else if (persons[i] instanceof Person){
    24. }else{
    25. System.out.println("你的类型有误,请自行判断...");
    26. }
    27. }
    28. }
    29. }

    这里要巧妙的运用instanceof判断运行类型,然后对其进行向下转型的处理,如果运行类型是Person则不进行处理


    11.多态参数

    其实在这里就已经体现出了参数的多态,cat和pig是Animal的子类,fish和rice是Food的子类。  


     

    1. public class Employee {
    2. private String name;
    3. private double salary;
    4. public Employee(String name, double salary) {
    5. this.name = name;
    6. this.salary = salary;
    7. }
    8. //得到年工资的方法
    9. public double getAnnual(){
    10. return 12 * salary;
    11. }
    12. public String getName() {
    13. return name;
    14. }
    15. public void setName(String name) {
    16. this.name = name;
    17. }
    18. public double getSalary() {
    19. return salary;
    20. }
    21. public void setSalary(double salary) {
    22. this.salary = salary;
    23. }
    24. }
    1. public class Manager extends Employee {
    2. private double bonus;
    3. public Manager(String name, double salary, double bonus) {
    4. super(name, salary);
    5. this.bonus = bonus;
    6. }
    7. public void manage() {
    8. System.out.println("经理 " + getName() + "is managing");
    9. }
    10. //重写获取年薪方法
    11. @Override
    12. public double getAnnual() {
    13. return super.getAnnual() + bonus;
    14. }
    15. public double getBonus() {
    16. return bonus;
    17. }
    18. public void setBonus(double bonus) {
    19. this.bonus = bonus;
    20. }
    21. }
    1. public class Worker extends Employee {
    2. public Worker(String name, double salary) {
    3. super(name, salary);
    4. }
    5. public void work() {
    6. System.out.println("普通员工 " + getName() + " is working");
    7. }
    8. @Override
    9. public double getAnnual() { //因为普通员工没有其他收入,则直接调用父类的方法。
    10. return super.getAnnual();
    11. }
    12. }

    那么我们就开始写测试类

    1. public class PloyParameter {
    2. public static void main(String[] args) {
    3. Worker tom = new Worker("tom", 2500);
    4. Manager milan = new Manager("milan", 5000, 200000);
    5. PloyParameter ployParameter = new PloyParameter();
    6. ployParameter.showEmpAnnual(tom);
    7. ployParameter.showEmpAnnual(milan);
    8. ployParameter.testWork(tom);
    9. ployParameter.testWork(milan);
    10. }
    11. /**
    12. * showEmpAnnual(Employee employee)
    13. * 实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [employee.getAnnual()]
    14. */
    15. public void showEmpAnnual(Employee employee) {
    16. System.out.println(employee.getAnnual());
    17. }
    18. }

    此时:ployParameter.showEmpAnnual(tom);这里我们传进去的tom,它的编译类型是Worker,运行类型也是Worker,那么传进去肯定会去找worker。

    那么我们传milan进去,就会给Manager绑定,因为有动态绑定机制。


    那么我们再写第二个方法:

    此时们将形参再写Employee,然后用instanceof判断运行类型,如果是Worker,直接调用e.work(),这里编译器会自动转换--->向下转型。

    那么继续用istanceof判断是不是Manager。

    1. public class PloyParameter {
    2. public static void main(String[] args) {
    3. Worker tom = new Worker("tom", 2500);
    4. Manager milan = new Manager("milan", 5000, 200000);
    5. PloyParameter ployParameter = new PloyParameter();
    6. ployParameter.showEmpAnnual(tom);
    7. ployParameter.showEmpAnnual(milan);
    8. ployParameter.testWork(tom);
    9. ployParameter.testWork(milan);
    10. }
    11. /**
    12. * showEmpAnnual(Employee employee)
    13. * 实现获取任何员工对象的年工资,并在 main 方法中调用该方法 [employee.getAnnual()]
    14. */
    15. public void showEmpAnnual(Employee employee) {
    16. System.out.println(employee.getAnnual());
    17. }
    18. //添加一个方法,testWork,如果是普通员工,则调用 work 方法,如果是经理,则调用 manage 方法
    19. public void testWork(Employee e){
    20. if (e instanceof Worker){
    21. ((Worker) e).work(); //有一个向下转型的操作
    22. }else if (e instanceof Manager){
    23. ((Manager) e).manage();
    24. }else{
    25. }
    26. }
    27. }

  • 相关阅读:
    Servlet请求转发与重定向
    痛心:实验室服务器被黑挖矿怎么办?
    jq命令用法总结
    FL Studio20.9.1水果中文版来啦 Win/Mac中文版FL水果萝卜
    面向对象(九) 多态 接口
    Electron -- 编写第一个Eletron程序
    怎么把pdf合并成一个pdf?认准这几个合并方法
    IIS发布网站,使用localhost无法调用Post、Put、Delete接口
    Flask初体验
    中国汽车在欧洲汽车安全测试中获得高分
  • 原文地址:https://blog.csdn.net/qq_44706176/article/details/126293870