什么是多态

主讲人:王少华       QQ群号:483773664

学习目标:

1)父类与子类间转换:向上转型

2)使用父类作为方法形参实现多态

3)使用父类作为返回值实现多态

一、子类到父类的转换(向上转型)

(一)基本数据之间的类型转换

1.自动进行类型转换

1
2
3
//将int型常量或变量的值赋给double型变量,可以自动进行类型转换
int i = 5;
double dl = i;

2.强制类型的转换

类型转换运算符是小括号,类型转换运算符的用法是

typevariable

 

1
2
3
//将double型常量或变量的值赋给int型变量,进行强制类型转换
double d2 = 3.14;
int a = (int) d2;

3.基本数据类型转换注意事项

基本类型之间的转换只能在数值类型之间进行,这里所说的数值类型包括:整数型、字符型和浮点型。但数值类型和布尔类型之间不能进行类型转换。

(二)引用数据类型转型

数据类型转换不但存在于基本数据类型之间,还存在于引用类型之间,但引用数据类型转型存在一些规则

1.引用类型之间的转换只能在具有继承关系的两个类这间进行。

Person person = new Dog();  //Error

2.将一个父类引用指向一个子类对象,称为向转型(upcasting,自动进行类型转换。

Pet pet = new Dog();

二、使用父类作为方法形参

用父类作为方法的形参,是Java中实现和使用多态的主要方式之一。

(一)解决给宠物喂食的难题

1.Master

修改Master类,注释feed(Dog dog)feedPenguin penguin)方法,增加唯一的feed(Pet pet)方法,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Master {
    private String name = "";// 主人名字
    private int money = 0; // 元宝数
  
    /**
     * 有参构造方法。
     *
     * @param name
     *主人名字
     * @param money
     *元宝数
     */
    public Master(String name, int money) {
        this.name = name;
        this.money = money;
    }
  
    public void setName(String name) {
        this.name = name;
    }
  
    public void setMoney(int money) {
        this.money = money;
    }
  
    public int getMoney() {
        return money;
    }
  
    public String getName() {
        return name;
    }
  
    /**
     * 主人给宠物喂食。
     */
    public void feed(Pet pet) {
        pet.eat();
    }
}

2.Test:测试类

1
2
3
4
5
6
7
8
9
10
11
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("欧欧", "雪娜瑞");
        Penguin pgn = new Penguin("楠楠", "Q妹");
        dog.setHealth(80); // 设置健康值,以便正常喂食
        pgn.setHealth(80); // 设置健康值,以便正常喂食
        Master master = new Master("王先生", 100);
        master.feed(dog);// 主人给狗狗喂食
        master.feed(pgn);// 主人给企鹅喂食
    }
}


备注:

1)向上转型的规则:通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不是父类的方法;

2)使用多态的好处:减少代码量,提高代码的可扩展性。

3.验证:多态的扩展性

增加宠物Cat类,继承Pet类并重写eat()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Cat extends Pet{
    private String color;//颜色
    public Cat(String name, String color) {
        super(name);
        this.color = color;
    }
    
    public void setColor(String color) {
        this.color = color;
    }
  
    public String getColor() {
        return color;
    }
    /**
     *  实现吃饭方法
     */
    public void eat() {
        if(getHealth()>=100){
            System.out.println("狗狗"+this.getName() +"吃饱了,不需要喂食了!");
        }else{
            this.setHealth(this.getHealth()+4);
            System.out.println("猫咪"+this.getName() + "吃饱啦!体力增加4。");
        }
    }
}

4.Test:添加领养和喂食猫的语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("欧欧", "雪娜瑞");
        Penguin pgn = new Penguin("楠楠", "Q妹");
        Cat cat = new Cat("Tomcat", "黄色");
        dog.setHealth(80); // 设置健康值,以便正常喂食
        pgn.setHealth(80); // 设置健康值,以便正常喂食
        cat.setHealth(80); // 设置健康值,以便正常喂食
        Master master = new Master("王先生", 100);
        master.feed(dog);// 主人给狗狗喂食
        master.feed(pgn);// 主人给企鹅喂食
        master.feed(cat);// 主人给猫喂食
    }
}

(二)父类调用子类特有方法

1.需求:

假设主要可以同时给狗和企鹅喂食,但只能和狗玩飞盘游戏,只能和企鹅玩游泳游戏。

1)Penguin类添加swim方法

2.实现:

Dog类添加catchingFlyDisc()

1
2
3
4
5
6
7
public void catchingFlyDisc(){
        if(super.getLove()>=100){
            super.setLove(100);
        }else {
            super.setLove(super.getLove()+10);
        }
    }

在测试类中,通过Pet调用Dog类中的cathingFlyDisc

3.原因及结论

因为主人类只晓得它是一个宠物,而不知道它是狗还是企鹅,所以主人不知道应该跟这个宠物玩什么游戏。因此,在多态中,通过父类引用变量无法调用子类特有的方法

三、使用父类作为方法返回值

使用父类作为方法的返回值,是Java中实现和使用多态的另一种方式。

(一)需求

使用父类作为方法返回值的方式,来实现主人领养宠物的功能

1)Master类添加getPet(String typeId)方法,实现领养功能

2)创建测试类,根据主人选择宠物的类型编号来领养宠物

3)调用给宠物喂食,测试是否正确领养

(二)实现

1.Master

修改Master类添加getPet(String typeId)方法,以父类Pet作为方法返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
     * 主人领养宠物
     * @param typeId 宠物编号
     * @return
     */
    public Pet getPet(int typeId){
        Pet pet=null;
        if(typeId==1){
            pet= new Dog("欧欧", "雪娜瑞");
        }elseif(typeId==2){
            pet  = new Penguin("楠楠", "Q妹");
        }
        return pet;
    }

2.Test

Test类中,添加领养信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test {
    public static void main(String[] args) {
        Master master = new Master("王先生", 100);
        Scanner input = new Scanner(System.in);
        System.out.println("欢迎您来到宠物店!");
        System.out.print("请选择要领养的宠物类型:(1、狗狗 2、企鹅)");
        int typeId = input.nextInt();
        Pet pet = master.getPet(typeId);
        if (pet != null) {
            System.out.println("领养成功!");
             pet.setHealth(80); //设置健康值,以便正常喂食
            master.feed(pet);
        } else {
            System.out.println("对不起,没有此类型的宠物,领养失败");
        }
    }
}

四、总结

(一)实现多态的条件

通过以上示例对多态功能的详解,总结实现多态的3个条件

1)继承的存在,继承是多态的基础,没有继承就没有多态

2)子类重写父类方法,多态下调用子类重写后的方法;

3)父类引用变量指向子类对象,不能调用子类对象特有的方法

(二)多态中的方法

1)通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不是父类的方法

2)通过父类引用变量无法调用子类特有的方法