多态的本质与使用

目录

一、什么是多态?

二、多态前提下成员的访问特点

三、多态使用场景

四、多态弊端的解决


一、什么是多态?

多态的本质 : 引用数据类型 子父类/实现类和父接口 之间的类型转换问题;

因为基本数据类型有 "类型转换" 这个特性;
    前提 : 基本数据类型之间有大小关系 [double > float > long > int > byte,short,char]
    自动提升 : 大类型的变量接收小类型的值/变量
    强制转换 : 小类型的变量强制接收大类型的值/变量   [有弊端 : 不推荐使用]
        
Java中引用数据类型的种类繁多,也想有想Java基本数据类型 '类型转换' 这样的特性 
    前提 : 必须有继承关系/实现关系 -> 必要条件
    向上转型 : 父引用接收子类对象 : Fu fu = new Zi(); 
    向下转型 : 子引用"强制"接收父引用 : Zi zi = (Zi) fu; [有风险 : 把父引用转换成了不同类型的子类对象]

public class Demo {
    public static void main(String[] args) {
        //向上转型 : 父类引用直接接收子类对象
        Animal animal = new Dog(); //任意一条狗都是一只动物

        //向下转型 : 子引用强制接收父引用 [前提 : 这个父引用确实接收的是一只狗对象]
        Dog dog = (Dog)animal;

        //报错 : 类型转换异常
        //Cat cat = (Cat)animal;

        //向上转型 : 父类引用直接接收子类对象
        Fu fu = new Zi();

        //向下转型 : 子引用强制接收父引用
        Zi zi = (Zi) fu;

    }
}

class Animal{

}

class Dog extends Animal{

}

class Cat extends Animal{

}

interface Fu{

}

class Zi implements Fu{

}

二、多态前提下成员的访问特点

多态前提下成员变量的访问特点 : 就近原则 
多态前提下构造方法的访问特点 : 子类要加载优先加载父类
    
多态前提下成员方法的访问特点 : 动态绑定    
    当父引用启动方法时,具体执行的是哪个方法要看父引用具体接收的是哪个类型的对象;

    注意!父引用无法访问子类特有的成员 ! [因为子类对象的功能才是最多的]

三、多态使用场景

1. 把父引用作为方法的形参,那么传入方法实参的对象类型有 n + 1 种;
    // 举例 : 
        public void show(Object obj){//传入任意类型的实参对象
            
        }
2. 把父类型作为容器的数据类型,那么容器内可以存储的元素类型有 n + 1 种; //举例 : Object[] , ArrayList<Object>
3. 把父类型作为方法的返回值类型 , 那么方法内返回结果的对象类型有 n + 1 种; 
    //举例 : 
        public Object get(){
            return 任意类型的结果;
        }
4. 异常体系中 : 抛出父类型异常,子类型异常也抛出; / 捕获父类型异常,子类型异常也一并捕获了;

/*
    动态绑定 :
        父引用调用方法,动态的绑定等号右边真实对象的类型

    多态的弊端 :
        父引用不能访问子类的特有成员
 */
public class Demo {
    public static void main(String[] args) {
        //创建多态对象 [这么用的很少]
        Animal a1 = new Dog();
        Animal a2 = new Cat();

        //对象调用方法 : 看对象的真实类型[等号右边具体的类型]
        a1.eat();
        //a1.lookHome();
        a2.eat();
        System.out.println("--------------------------");
        //动态绑定真实的使用场景 -> 多态的真实使用场景
        Dog dog = new Dog();
        Cat cat = new Cat();

        useAnimal(dog);
        useAnimal(cat);

    }
    /*
        参数传递时 有多态:
            1. Animal animal  = new Dog();
            2. Animal animal  = new Cat();
     */
    public static void useAnimal(Animal animal){
        animal.eat();
    }
}

class Animal{
    public void eat(){
        System.out.println("动物吃东西");
    }
}

class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    public void lookHome(){

    }
}

class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃罐头");
    }
}

四、多态弊端的解决

多态弊端的解决 : 向下转型 
    向下转型 : 子引用"强制"接收父引用 : Zi zi = (Zi) fu; [有风险 : 把父引用转换成了不同类型的子类对象]
如何判断一个引用是哪个类型的对象 : 
    1. instanceof -> 格式 : 引用 instanceof 类型 -> 结果 : boolean 类型
        
    2. 通过字节码对象判断类型 -> 原因 : 因为一个类的字节码对象只有一个! [通过不同方式获取类的字节码对象如果是同一个对象,那么说明类型是一致的!]
       获取类字节码对象的方式 :
            a. 对象.getClass() : 获取此对象所属类的字节码对象
            b. 类名.class : 获取此类的字节码对象    
               if(对象名.getClass() == 类名.class){
                   //能进来说明 前面的对象是后面那个类型的
               }
/*
    如何解决多态的弊端 :
        向下转型
 */
public class Demo {
    public static void main(String[] args) {
//        Dog dog = new Dog();
//        useAnimal(dog);
        //匿名[没有对象名的]对象
        useAnimal(new Dog());

        //useAnimal(new Cat());
    }

    public static void useAnimal(Animal animal){//= new Dog();
        animal.eat();

        //启动狗和猫类的特有行为
        //animal.lookHome(); //多态的弊端 : 父引用无法访问子类特有成员
        //向下转型有风险 : 提前做判断 -> 是狗转狗 , 是猫转猫
        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.lookHome();
        }

        if (animal instanceof Cat){//false
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }

        if (animal.getClass() == Dog.class){
            Dog dog = (Dog) animal;
            dog.lookHome();
        }

        if (animal.getClass() == Cat.class){
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
    }
}
class Animal{
    public void eat(){
        System.out.println("动物吃东西");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    public void lookHome(){
        System.out.println("狗看家");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃罐头");
    }

    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值