• 06.多态


    6. 多态

    多态是同一个行为具有多个不同表现形式或形态的能力。

    实际开发中,多态的体现更多的是里氏代换原则&依赖倒置原则使用,即针对接口编程,依赖于抽象而不依赖具体,以及任何基类/父类可以出现的地方,子类一定可以出现。

    java中多态的体现:

    使用父类型引用指向子类对象;(使用接口类型引用指向实现类对象)

    使用前提

    ​多态存在的三个必要条件

    • 继承
    • 重写
    • 父类引用指向子类对象

    优点

    1. 使用多态可以提高程序的扩展性;
    2. 提高代码的复用性,降低程序的冗余性;
    3. 消除类型之间的耦合关系
    4. 可替换性
    5. 可扩充性
    6. 接口性
    7. 灵活性
    8. 简化性

    常用场景

    1. 多态参数
    2. 多态数组
    abstract class Animal
    {
    	public abstract void eat();
    	public abstract void sleep();
    }
    
    class Dog extends Animal
    {
    	public void eat(){
    		System.out.println("狗吃肉..");
    	}
    
    	public void sleep(){
    		System.out.println("狗zzZZ");
    	}
    }
    
    class Cat extends Animal
    {
    	public void eat(){
    		System.out.println("猫吃鱼..");
    	}
    
    	public void sleep(){
    		System.out.println("猫zzZZ");
    	}
    }
    
    class TestPolymorphism1 
    {
    	public static void main(String[] args) 
    	{
    		//Dog d = new Dog();	//本态引用
    		Animal a = new Dog();	//多态引用	--> 此处发生多态了
    
    		/*
    			多态的使用情况之非静态方法:
    
    				编译期(编译阶段):看左边(父类型)
    
    				运行期(运行阶段):看右边 --> 运行子类重写父类以后的内容
    					
    		*/
    		a.eat();
    		a.sleep();
    
    		//调用检查狗的方法
    		//checkDog(d);	//相当于:Dog d = d --> Dog d = new Dog()	本类引用
    
    		//调用检查动物的方法,目的为了检查一条狗
    		//checkAnimal(d);	
    		//相当于:Animal a = d --> Animal a = new Dog()	多态引用
    		//checkAnimal(new Cat());	
    		//此处发生了多态	Animal a = new Cat()
    	}
    
    	/*
    		如果有100种动物我都需要对其进行检查,是不是需要定义100个check方法;
    		这样做程序冗余度很高(阅读性很差),并且扩展性也不理想;
    
    		能不能一个check方法就解决检查100个动物的需求
    	*/
    
    	/*
    		以下这种多态的使用领域:
    				多态参数	√
    				多态数组
    
    		好处:
    			降低了程序代码的冗余度,提高了代码的阅读性;
    			并且此功能变的极具扩展性
    	*/
    	//检查动物
    	public static void checkAnimal(Animal a){
    		//检查项目:吃、睡
    		a.eat();
    		a.sleep();
    	}
    	/*
    	//检查狗
    	public static void checkDog(Dog d){
    		//检查项目:吃、睡
    		d.eat();
    		d.sleep();
    	}
    	//检查猫
    	public static void checkCat(Cat c){
    		//检查项目:吃、睡
    		c.eat();
    		c.sleep();
    	}
    	*/
    }
    
    
    • 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
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    多态数组举例:

    /*
    	演示多态的使用领域之多态数组
    
    	好处:
    		降低了程序代码的冗余度,提高了代码的阅读性;
    		并且此功能变的极具扩展性
    */
    //几何图形类
    abstract class GrometricObject
    {
    	abstract double findArea();
    }
    
    //圆
    class Circle extends GrometricObject
    {
    	private double radius;	//半径
    
    	Circle(double radius){
    		this.radius = radius;
    	}
    
    	Circle(){
    	
    	}
    
    	//重写父类GrometricObject中的抽象方法
    	double findArea(){
    		return Math.PI * radius * radius;
    	}
    }
    
    class Rectangle extends GrometricObject
    {
    	private double length;	//长度
    	private double width;	//宽度
    
    	Rectangle(double length,double width){
    		this.length = length;
    		this.width = width;
    	}
    
    	Rectangle(){
    	
    	}
    
    	//重写父类GrometricObject中的抽象方法
    	double findArea(){
    		return length * width;
    	}
    }
    class TestPolymorphism2 
    {
    	public static void main(String[] args) 
    	{
    		Circle[] cirs = new Circle[4];		//定义圆数组,内部存储4个圆对象
    		
    		Rectangle[] recs = new Rectangle[3];	//定义矩形数组,内部存储3个矩形对象
    
    
    		GrometricObject[] gos = new GrometricObject[7];	//定义几何图形数组,内部可以存储7个任意的几何图形
    		gos[0] = new Circle(1.0);	//此处发生多态
    		gos[gos.length - 1] = new Rectangle(2.0,3.0);	//此处发生多态
    
    		//遍历几何图形数组
    		for(int i = 0; i <= gos.length - 1;i++){
    			//System.out.println(gos[i].findArea());
    			System.out.println(gos[i]);
    		}
    	}
    }
    
    
    • 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
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    多态的弊端:

    只能使用父类中已经定义的成员变量和函数,不能使用子类中独有的变量或函数;如果需要调用子类独有的成员,就需要先进行强转(向下转型);可能在运行的过程中会出现java.lang.ClassCastException异常
    为了避免其发生,我们可以使用instanceof关键字

    /*
    	演示多态的弊端:
    		强制向下转型可能出现java.lang.ClassCastException,
    		为了避免其出现,我们可以使用instanceof关键字来把控
    
    		格式:
    			需要被转换类型的对象 instanceof 需要转换成的类型
    
    			如果是,则返回true;
    			如果不是,返回false
    */
    abstract class Person
    {
    	abstract void eat();
    	abstract void walk();
    }
    
    class Man extends Person
    {
    	//独有属性
    	boolean isSmoking;
    
    	void eat(){
    		System.out.println("大口吃肉,大碗喝酒");
    	}
    
    	void walk(){
    		System.out.println("大摇大摆的走路");
    	}
    
    	//独有方法
    	void entertainment(){
    		System.out.println("花天酒地!!");
    	}
    }
    
    class Woman extends Person
    {
    	//独有属性
    	boolean isBeauty;
    
    	void eat(){
    		System.out.println("细嚼慢咽");
    	}
    
    	void walk(){
    		System.out.println("婀娜多姿的走路");
    	}
    
    	//独有方法
    	void shopping(){
    		System.out.println("买买买...");
    	}
    }
    
    class TestPolymorphism3 
    {
    	public static void main(String[] args) 
    	{
    		//Person p = new Woman();	//此处发生多态	引用数据类型:小 -> 大	向上转型(造型)
    
    		/*
    		int i = 20;
    		short s = 200;
    
    		i = s;	//基本数据类型:小 -> 大	自动类型转换
    		*/
    
    		//p.eat();
    		//p.walk();
    		
    		/*
    			对于多态性 --> 非静态方法:
    						编译期看父类型,由于shopping()不存在于父类Person中,
    						所以编译出错
    		*/
    		//p.shopping();
    		
    		/*
    			需求:
    				我需要在现有代码的基础上调用shopping(),该怎么做?
    				将p(Person类型) -> Woman类型就可以了
    				大 -> 小	向下转型(造型)
    
    				强制向下转型 --> 强制类型转换
    				格式:
    					需要被转换成的类型 引用名 = (需要被转换成的类型)变量名;
    		*/
    		//Woman w = (Woman)p;
    
    		//w.shopping();
    
    
    		/*
    			由于Man和Woman都是Person类型的子类型,所以w.shopping()代码没有问题;
    			但是运行的过程中报错了,
    			发生了:java.lang.ClassCastException -->  Man cannot be cast to Woman
    			因为具体的对象是一个实实在在的Man对象,没有shopping方法
    
    			问题出现:
    				强制类型转换(向下转型)有风险,使用需谨慎!!
    
    				可以使用instanceof关键字来控制避免出现ClassCastException
    
    				格式:
    					需要被转换类型的对象 instanceof 需要转换成的类型
    
    					如果是,则返回true;
    					如果不是,返回false
    
    		*/
    		Person p1 = new Man();	//此处发生多态
    		
    		
    		//Woman w1 = (Woman)p1;
    		//w1.shopping();
    
    		test(p1);
    		test(new Woman());	//Person p = new Woman()
    
    	}
    
    	public static void test(Person p){
    		//判断
    		if(p instanceof Man){
    			Man m = (Man)p;
    			m.entertainment();
    		}else if(p instanceof Woman){
    			Woman w = (Woman)p;
    			w.shopping();
    		}
    	}
    }
    
    
    • 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
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134

    类型转换

    1. 自动向上转型:

      在使用多态时,将子类型对象赋值给父类型引用,相当于将对象的类型提升为父类型,叫做向上转型;因为这个过程可以自动进行,所以叫做自动向上转型;

      如:

      class  Fu{}
      
      class  Zi  extends Fu{}
      
      Fu  f  =  new  Zi();//就是发生了自动向上转型
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. 强制向下转型:

      将父类型引用(对象)赋值给子类型引用,相当于将父类型向下转换成子类型,叫做向下转型;这个过程不能自动进行,需要强制进行,所以叫做强制向下转型;

      如:

      class  Fu{}
      class  Zi  extends Fu{}
      
      Fu   f    =   new  Fu();
      Zi   z  =  (Zi)f;//这里将父类型引用转换为子类引用,发生了强制向下转型;
      
      • 1
      • 2
      • 3
      • 4
      • 5

    结论:使用强制向下转型,可以解决多态使用中的弊端;

    结论:在强制向下转型前先使用instanceof关键字进行判断,可以避免出现类型转换异常;

  • 相关阅读:
    大数据:Shell的操作
    Acrel-1200分布式光伏运维平台
    GIt后悔药:还原提交的操作(谨慎操作)
    如何在线webp转JPG/PNG图片格式
    git本地仓库及远端仓库推送【linux】
    Dynamics 365应用程序开发 - 6. 使用Microsoft Flow自动化业务流程
    Java JVM 运行机制及基本原理
    获取任意时间段内周、季度、半年的二级联动
    【Eclipse】安装教程
    C++ 重载运算符和重载函数
  • 原文地址:https://blog.csdn.net/qq2512446791/article/details/125555514