【Java知识点系列】:多态

本文节选自我的另一篇文章Java总结六:面向对象编程(中)

📚问题引导

请编写一个程序,Master类中有一个feed (喂食)方法,可以完成主人给动物喂食物的信息。
在这里插入图片描述
☕️Food父类

package com.hj.第八章面向对象编程.多态;

public class Food {
    private String name;
    public Food(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

☕️Fish子类

package com.hj.第八章面向对象编程.多态;

public class Fish extends Food {
    public Fish(String name) {
        super(name);
    }
}

☕️Bone子类

package com.hj.第八章面向对象编程.多态;

public class Bone extends Food {
    public Bone(String name) {
        super(name);
    }
}

☕️Rice子类

package com.hj.第八章面向对象编程.多态;

public class Rice extends Food {
    public Rice(String name) {
        super(name);
    }
}

☕️Animal父类

package com.hj.第八章面向对象编程.多态;

public class Animal {
    private String name;
    public Animal(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

☕️Dog子类

package com.hj.第八章面向对象编程.多态;

public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
}

☕️Cat子类

package com.hj.第八章面向对象编程.多态;

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
}

☕️Pig类

package com.hj.第八章面向对象编程.多态;

public class Pig extends Animal {
    public Pig(String name) {
        super(name);
    }
}

利用传统方式解决此问题:
☕️Master类

package com.hj.第八章面向对象编程.多态;

public class Master {
    private String name;

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //主人给小狗 喂食 骨头
    public void feed(Dog dog, Bone bone) {
    System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());
    }
}

☕️mian方法:

package com.hj.第八章面向对象编程.多态;

public class Poly01 {
    public static void mian(String[] args){
        Master tom=new Master("Tom");
        Dog dog=new Dog("大黄");
        Bone bone=new Bone("大棒骨");
        tom.feed(dog,bone);
    }
}

运行结果:

主人 Tom 给 大黄 吃 大棒骨

如果接下来我们想让猫咪吃鱼,这时就会遇到麻烦。我们需要重载一个feed(),注释掉之前狗狗的feed()。

package com.hj.第八章面向对象编程.多态;

public class Master {
    private String name;

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //主人给小狗 喂食 骨头
    // public void feed(Dog dog, Bone bone) {
    //System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());
    }
    //主人给 小猫喂 黄花鱼
    public void feed(Cat cat, Fish fish) {
    System.out.println("主人 " + name + " 给 " + cat.getName() + " 吃 " + fish.getName());
    }
    //如果动物很多,食物很多
    //===> feed 方法很多,不利于管理和维护
    //Pig --> Rice
    //Tiger ---> meat ... //... }
}

如果动物很多,食物很多,feed 方法就会很多,不利于管理和维护。这时我们可以利用多态机制来解决问题。
☕️利用多态机制的Master类:

package com.hj.第八章面向对象编程.多态;

public class Master {
    private String name;

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //使用多态机制,可以统一的管理主人喂食的问题
    //animal 编译类型是 Animal,可以指向(接收) Animal 子类的对象
    //food 编译类型是 Food ,可以指向(接收) Food 子类的对象
    public void feed(Animal animal, Food food) {
        System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
    }
}
package com.hj.第八章面向对象编程.多态;

public class Poly01 {
    public static void main(String[] args){
        Master tom=new Master("Tom");
        Dog dog=new Dog("大黄");
        Bone bone=new Bone("大棒骨");
        tom.feed(dog,bone);

        Cat cat=new Cat("小花猫");
        Fish fish=new Fish("黄花鱼");
        System.out.println("=================");
        tom.feed(cat,fish);
    }
}

运行结果:

主人 Tom 给 大黄 吃 大棒骨
=================
主人 Tom 给 小花猫 吃 黄花鱼

📚多态基本介绍

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

📚多态的具体体现

🌍1. 方法的多态 :重写和重载就体现多态
☕️代码:

public class PloyMethod {
    public static void main(String[] args) {
        //方法重载体现多态
        A a = new A();
        //这里我们传入不同的参数,就会调用不同 sum 方法,就体现多态
        System.out.println(a.sum(10, 20));
        System.out.println(a.sum(10, 20, 30));
        //方法重写体现多态
        B b = new B();
        a.say();
        b.say();
    }
}
class B { //父类
    public void say() {
        System.out.println("B say() 方法被调用...");
    }
}
class A extends B {//子类
    public int sum(int n1, int n2){//和下面 sum 构成重载
        return n1 + n2;
    }
    public int sum(int n1, int n2, int n3){
        return n1 + n2 + n3;
    }
    public void say() {
        System.out.println("A say() 方法被调用...");
    }
}

运行结果:

30
60
A say() 方法被调用...
B say() 方法被调用...

🌍2. 对象的多态 (核心)

🌵一个对象的编译类型和运行类型可以不一致
🌵编译类型在定义对象时,就确定了,不能改变
🌵运行类型是可以变化的.
🌵编译类型看定义时=号的左边,运行类型看=号的右边

Animal animal = new Dog(); (animal编译类型是Animal,运行类型Dog)
animal = new Cat(); 【animal的运行类型变成了Cat,编译类型仍然是 Animal】

Animal父类

package com.hj.第八章面向对象编程.多态.对象的动态关键点;

public class Animal {
    public void cry(){
        System.out.println("Animal cry() 动物在叫~~");
    }
}

Dog子类

package com.hj.第八章面向对象编程.多态.对象的动态关键点;

public class Dog extends Animal {
    public void cry() {
        System.out.println("Dog cry() 小狗汪汪叫...");
    }
}

Cat子类

package com.hj.第八章面向对象编程.多态.对象的动态关键点;

public class Cat extends Animal{
    public void cry(){
        System.out.println("Cat cry() 小猫喵喵叫...");
    }
}

PolyObject类:

package com.hj.第八章面向对象编程.多态.对象的动态关键点;

public class PolyObject {
    public static void main(String[] args){
        //体验对象多态特点
        //animal编译运行就是Animal,运行类型Dog
        Animal animal=new Dog();
        //因为运行时,执行到改行时,animal运行类型就是Dog,所以Cry就是Dog的Cry
        animal.cry();//Dog cry() 小狗汪汪叫...
        //animal 编译类型 Animal,运行类型就是 Cat
        animal = new Cat();
        animal.cry(); //Cat cry() 小猫喵喵叫...
    }
}

运行结果:

Dog cry() 小狗汪汪叫...
Cat cry() 小猫喵喵叫...

📚多态注意事项和细节讨论

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

public class Animal {
    String name = "动物";
    int age = 10;
    public void sleep(){
        System.out.println("睡");
    }
    public void run(){
        System.out.println("跑");
    }
    public void eat(){
        System.out.println("吃");
    }
    public void show(){
        System.out.println("hello,你好");
    }
}

Dog类:

public class Dog extends Animal {//Dog 是 Animal 的子类
}

Cat类:

public class Cat extends Animal {
    public void eat(){//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){//Cat 特有方法
        System.out.println("猫抓老鼠");
    }
}

📚 多态的向上转型

🌵本质:父类的引用指向了子类的对象
🌵语法:父类类型 引用名=new子类类型();
🌵特点:编译类型看左边,运行类型看右边
可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员;最终运行效果看子类的具体实现!

package com.hj.第八章面向对象编程.多态.向上转型;

public class PolyDetail {
    public static void main(String[] args) {
	    //向上转型: 父类的引用指向了子类的对象
	    //语法:父类类型引用名 = new 子类类型();
        Animal animal = new Cat();
        Object obj = new Cat();//可以吗? 可以 Object 也是 Cat 的父类
	    //向上转型调用方法的规则如下:
	    //(1)可以调用父类中的所有成员(需遵守访问权限)
	    //(2)但是不能调用子类的特有的成员
	    //(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
	    //animal.catchMouse();错误
	    //(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法
	    //,然后调用,规则我前面我们讲的方法调用规则一致。
        animal.eat();//猫吃鱼..
        animal.run();//跑
        animal.show();//hello,你好
        animal.sleep();//睡
    }
}

🌍 向上转型调用方法的规则如下:

🌵可以调用父类中的所有成员(需遵守访问权限);
🌵但是不能调用子类的特有的成员,因为在编译阶段,能调用哪些成员,是由编译类型来决定的;
🌵最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法,然后调用,规则我前面我们讲的方法调用规则一致。

📚多态向下转型

🌵语法:子类类型 引用名= (子类类型)父类引用;
🌵只能强转父类的引用,不能强转父类的对象;
🌵要求父类的引用必须指向的是当前目标类型的对象;
🌵当向下转型后,可以调用子类类型中所有的成员;

package com.hj.第八章面向对象编程.多态.向上转型;

public class PolyDetail {
    public static void main(String[] args) {
	    //调用 Cat 的 catchMouse 方法
	    //多态的向下转型
	    //(1)语法:子类类型 引用名 =(子类类型)父类引用;
	    //问一个问题? cat 的编译类型 Cat,运行类型是 Cat
        Cat cat = (Cat) animal;
        cat.catchMouse();//猫抓老鼠
	    //(2)要求父类的引用必须指向的是当前目标类型的对象
	    //  Dog dog = (Dog) animal; 
        System.out.println("ok~~");
    }
}

🌍这里注意:
大家想想下面代码可以吗?

Dog dog = (Dog) animal; //可以吗?

不行!!!因为:父类的引用必须指向的是当前目标类型的对象,它已经是猫了不可能变成狗!
运行后出错:
在这里插入图片描述
📚属性没有重写之说!属性的值看编译类型

package com.hj.第八章面向对象编程.多态.多态的细节;

public class PolyDetail02 {
    public static void main(String[] args) {
        //属性没有重写之说!属性的值看编译类型
        Base base = new Sub();//向上转型
        System.out.println(base.count);//看编译类型 10
        Sub sub = new Sub();
        System.out.println(sub.count);//20
    }
}
class Base { //父类
    int count = 10;//属性
}
class Sub extends Base {//子类
    int count = 20;//属性
}

运行结果:

10
20

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

package com.hj.第八章面向对象编程.多态.多态的细节;

public class PolyDetail03 {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb instanceof BB);// true
        System.out.println(bb instanceof AA);// true
        // instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型
        //aa 编译类型 AA, 运行类型是 BB
        //BB 是 AA 子类
        AA aa = new BB();
        System.out.println(aa instanceof AA);// true
        System.out.println(aa instanceof BB);// true
        Object obj = new Object();
        System.out.println(obj instanceof AA);//false
        String str = "hello";
        //System.out.println(str instanceof AA);
        System.out.println(str instanceof Object);//true
    }
}
class AA {} //父类
class BB extends AA {}//子
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值