深入剖析 Java 多态之向上、向下转型

 2022-09-10
原文地址:https://blog.csdn.net/weixin_45554007/article/details/124092763

前言

为了解决代码的复用,提高扩展性


一、多态是什么?

同一个引用类型,使用不同的实例而执行不同操作。

二、多态的好处

1.解决代码复用
2.扩展性提高

三、多态实现前提条件

1.多态实现必须有继承
2.有方法重写
3.父类引用指向子类对象(父类引用 赋值的子类对象)

1、多态的两种体现形式

1)以父类类型作为方法的形参
代码如下(示例):

    //参数形式实现多态
        public  void  feed(Pet pet){
            //1.输出描述文字
            System.out.println("小姑娘喂养宠物....");
            //2.小狗吃东西
            //Dog dog = new Dog(); //创建一个新的对象, 该方法每调用一次,产生一个对象
            pet.eat();
        }
    //重写了父类的eat方法
        @Override
        public void eat() {
            System.out.println("小狗吃狗粮.....");
            //加健康值与亲密度
            //加健康值 + 10  在原来的健康值上加10
            //this.getHealth() 获取它原来的值
            this.setHealth(this.getHealth() + 10);
            //亲密度 + 5
            this.setLove(this.getLove() + 5);
        }

2)以父类类型作为方法的返回值类型

    public Pet lyPet(int num){
    	swich(num){
    	case 1:
    		return new Dog();
    	case 2:
    		return new Cat();
    	}
    	return null;
    }

聚合

多态: 迟绑定,动态绑定

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
多态:父类引用指向子类对象 代码表示:
Pet pet=new Dog();
Pet pet=new Cat();
3)Pet pet = new Dog();与Dog dog = new Dog(); 的区别

    由于在编译阶段,只是检查参数的引用类型。然而在运行时,
    java虚拟机(JVM)指定对象的类型并且运行该对象的方法。
    因此在下面的例子中,
    b.move()之所以能编译成功,是因为Pet类中存在move方法,所以编译成功,然而运行时,
    运行的是特定对象的方法,
    即运行的是Dog类的move方法。而对Dog c而言,编译阶段首先是去Dog中查找bark(),
    因此能编译成功,同时也能运行成功;但是对于b.bark()而言,首先是去Pet类中寻找bark(),
    因为找不到,因而编译错误。
     
    public class Person {
        public static class Pet {
            public void eat() {
                System.out.println("Pet中的eat方法");
            }
        }
     
        public static class Dog extends Pet{
            public void eat() {
                System.out.println("dog中的eat方法");
            }
     
            public void bark() {
                System.out.println("狗可以吠叫");
            }
        }
     
        public static void main(String args[]) {
            Pet a = new Pet(); // Pet 对象
            Pet b = new Dog(); // Dog 对象
            Dog c = new Dog();
            a.move();// 执行 Pet 类的方法
            b.move();// 执行 Dog 类的方法
            b.bark();
            c.bark();
     
        }
     
    }

四、向上转型

1)类结构图

202209102325108111.png
父(辈)类类型 变量 接收一个子类对象, 把子类对象赋值给父类引用
向上转型,自动类型转换
2)优缺点
1.优点:实现多态

202209102325121652.png
2.缺点:父类的引用调用不到子类特有的属性/方法

     public static void main(String[] args) {
            //使用子类对象接收
            Dog dog = new Dog("旺财",70,50,"泰迪");
            //dog调用特有属性方法
            dog.setType("牧羊犬");  //没有问题
            //向上转型: 把子类对象赋值给父类引用
            Pet pet = dog;
            //使用父类引用调用子类特有属性方法  调用不到
            //pet.setType("泰迪");  //报错
            
        }

202209102325133283.png

五、向下转型

1.语法
把父类转换为子类, 需要强制类型转换

    子类 子类变量名 =  (子类名)父类对象;

2.目的
需要调用子类特有的属性和方法
3.instanceof使用
如果直接强制转换可能出现ClassCastException

202209102325143854.png
从而就Java提供了instanceof
instanceof 使用场景, 当你需要向下转型的时候
java提供 instanceof 对象 instanceof 类名/接口名 判断对象是否是右边的类或者接口的对象,或者是子类对象 结果: boolean ture: 表示对象是类的一个对象,或者子类对象 false 否则

     public static void main(String[] args) {
            Dog dog = new Dog();
            Penguin penguin = new Penguin();
            Pet p1 = penguin;
    
    
            System.out.println(dog instanceof  Dog); //true
            System.out.println(dog instanceof  Pet); //true
    
            System.out.println(penguin instanceof  Penguin); //true
            System.out.println(penguin instanceof  Pet);  //true
    
            System.out.println(p1 instanceof  Penguin); //true
            System.out.println(p1 instanceof  Dog);  //false
            System.out.println(p1 instanceof  Pet);  //true
        }

六、总结

1).多态的两种形式:
1.以父类类型作为方法的形参
2.以父类类型作为方法的返回值类型
2).向上转型:
可直接转但是不能 使用子类特有的属性和方法
3).向下转型
不能直接转,需要用到instanceof关键字,应用场景就是需要调用子类特有方法与属性