Java之多态机制

一、多态基础语法
1、关于多态中涉及的概念:
1)向上转型(upcasting)
子类型—>父类型
又称为:自动类型转换
2)向下转型(downcasting)
父类型—>子类型
又称为:强制类型转换【需要加强制类型转换符】
【注】
无论是向上转型还是向下转型,两种类型之间必须要有继承关系
没有继承关系,程序是无法编译通过的。
2、父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的形态/状态,
这种机制可以成为一种多态语法机制。
3、在强制类型转换的时候会发生java.lang.ClassCastException,也就是说"向下转型"存在隐患(编译过了,但是运行错了!)
4、向上转型只要编译通过,运行一定不会出问题
5、向下转型编译通过,运行可能错误
6、怎么避免向下转型出现的ClassCastException呢?
使用instanceof运算符可以避免出现以上的异常
7、instanceof运算符怎么用呢?
1)语法格式
(引用 instanceof 数据类型名)
2)以上运算符的执行结果类型是布尔类型,结果可能是true/false
3)关于运算结果true/false:
假设:(a instanceof Animal)
true表示:
a这个引用指向的对象是一个Animal类型
false表示:
a这个引用指向的对象不是一个Animal类型
8、Java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判断,
避免ClassCastException异常的发生。这是一种编程的好习惯。

二、多态的作用
降低程序的耦合度,提高程序的扩展力
能使用多态尽量使用多态类
父类型引用指向子类型对象

public class Animal {

	public void move(){
		System.out.println("动物在移动");
	}
}

//Cat类
public class Cat extends Animal{

	@Override
	public void move() {
		System.out.println("猫在走猫步");
	}

	//不是从父类中继承过来的方法
	//这个方法是子类对象特有的行为【不是所有的动物都能抓老鼠】
	public void catchMouse(){
		System.out.println("猫抓老鼠!");
	}
}

//Bird类
public class Bird extends Animal {

	@Override
	public void move() {
		System.out.println("鸟儿在飞翔!");
	}

	public void fly(){
		System.out.println("Bird fly");
	}
}
		
/*
Animal、Cat、Bird三个类之间的关系
     Cat继承Animal
     Bird继承Animal
     Cat和Bird之间没有任何继承关系
*/	 
public class polymorphicTest {

	public static void main(String[] args) {
		//不使用多态
		Animal a = new Animal();
		a.move();

		Cat c = new Cat();
		c.move();
		c.catchMouse();

		Bird b = new Bird();
		b.move();

		//使用多态语法机制
		/**
		 * 1、Animal和Cat之间存在继承关系
		 * 2、Cat is a Animal
		 * 3、new Cat()创建的对象的类型是Cat,a2这个引用的数据类型是Animal,可见他们进行了类型转换
		 *    子类型转换成父类型,称为向上转型/upcasting,或者称为自动类型转换
		 * 4、java中允许这种语法,父类型引用指向子类型对象
		 *
		 *
		 */
		Animal a2 = new Cat();
		/**
		 * 1、Java程序永远都分为编译器和运行期
		 * 2、先分析编译阶段,再分析运行阶段,编译无法通过,根本是无法运行的
		 * 3、编译阶段编译器检查a2这个引用的数据类型为Animal,由于Animal.class
		 *   字节码当中有move()方法,所以编译通过了,这个过程我们称为静态绑定、编译阶段绑定,
		 *   只有静态绑定成功之后才有后续的运行。
		 * 4、在程序运行阶段,JVM堆内存当中首次创建的对象是Cat对象,那么以下程序
		 *    在运行阶段一定会调用Cat对象的move()方法,此时发生了程序的动态绑定、运行阶段绑定。
		 * 5、无论Cat类有没有重写move方法,运行阶段一定调用的是Cat对象的move方法,因为底层真实
		 *    对象就是Cat对象。
		 * 6、父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的形态/状态,
		 *    这种机制可以成为一种多态语法机制。
		 */
		a2.move();

		/**
		 * 分析以下程序为什么不能调用?
		 *      因为编译阶段编译器检查到a2的类型是Animal类型,
		 *      从Animal.class字节码文件当中查找catchMouse()方法,
		 *      最终没有找到该方法,导致静态绑定失败,没有绑定成功,
		 *      也就是说编译失败了,更就别谈运行了。
		 */
		//a2.catchMouse();

		/**
		 * 需求:
		 *    假设想让以上的对象执行catchMouse()方法,怎么办?
		 *        a2是无法直接调用的,因为a2的类型是Animal,Animal中没有catchMouse()方法,
		 *        我们可以将a2强制类型转换为Cat类型
		 *        a2的类型是Animal(父类),转换成Cat类型(子类),被称为向下转型/downcasting/强制类型转换
		 * 注:向下转型也需要两种类型之间必须有继承关系,不然编译报错,强制类型转换需要加强制类型转换符。
		 *
		 * 什么时候需要使用向下转型呢?
		 *      当调用的方法是子类类型中特有的,在父类型当中不存在,必须进行向下转型。
		 */
		Cat c2= (Cat)a2;
		c2.catchMouse();

		//父类型引用指向子类型对象【多态】
		Animal a3 = new Bird();
		/**
		 * 1、以下程序编译是没有问题的,因为编译器检查到a3的数据类型是Animal
		 *    Animal和Cat之间存在继承关系,并且Animal是父类型,Cat是子类型,
		 *    父类型转换成子类型叫做向下转型,语法合格。
		 * 2、程序虽然编译通过了,但是程序在运行阶段会出现异常,因为JVM堆内存当中
		 *    真实存在的对象是Bird类型,Bird对象无法转换成Cat对象,因为两种类型之间
		 *    不存在任何继承关系,此时出现了著名的异常:
		 *          java.lang.ClassCastException
		 *          类型转换异常,这种异常总是在"向下转型"的时候发生。
		 */
		//Cat c3 = (Cat)a3;

		/**
		 * 1、以上异常只有在强制类型转换的时候会发生,也就是说"向下转型"存在隐患(编译过了,但是运行错了!)
		 * 2、向上转型只要编译通过,运行一定不会出问题:Animal a = new Cat();
		 * 3、向下转型编译通过,运行可能错误:Cat c3 = (Cat)a3;
		 * 4、怎么避免向下转型出现的ClassCastException呢?
		 *      使用instanceof运算符可以避免出现以上的异常
		 * 5、instanceof运算符怎么用呢?
		 *   1)语法格式
		 *      (引用 instanceof 数据类型名)
		 *   2)以上运算符的执行结果类型是布尔类型,结果可能是true/false
		 *   3)关于运算结果true/false:
		 *      假设:(a instanceof Animal)
		 *      true表示:
		 *          a这个引用指向的对象是一个Animal类型
		 *      false表示:
		 *          a这个引用指向的对象不是一个Animal类型
		 * 6、Java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判断,
		 *    避免ClassCastException异常的发生。这是一种编程的好习惯。
		 */
			if(a3 instanceof Cat){//a3是一个Cat类型的对象
				Cat c3 = (Cat)a3;
				c3.catchMouse();
			}else if(a3 instanceof Bird){//a3是一个Bird类型的对象
				Bird b2 = (Bird)a3;
				b2.fly();
			}
	}
}

【多态的作用】
/**
 * 宠物小狗
 */
public class Dog extends Pet {
	public void eat(){
		System.out.println("小狗正在啃骨头");
	}
}

//宠物小猫
public class Cat extends Pet{

	public void eat() {
		System.out.println("小猫正在吃🐟");
	}
}

/**
 * 宠物
 */
public class Pet {

	public void eat(){

	}
}

/**
 * 主人类
 */
//这种方式没有使用java语言当中的多态机制,存在的缺点:Master的扩展力很差,因为只要加一个新的宠物,Master类就需要添加新的方法。
/*
public class Master {

	//喂养宠物的方法
	public void feed(Cat c){
		c.eat();
	}
	public void feed(Dog d){
		d.eat();
	}
}
//Master和Cat、Dog这两个类型的关联程度很强,耦合度很高、扩展力很差。
/*
public class Master {
	//喂养宠物的方法
	public void feed(Cat c){
		c.eat();
	}
	public void feed(Dog d){
		d.eat();
	}
 }
 */

//降低程序的耦合度【解耦合】,提高程序的扩展力
public class Master {
	//Master主人类面向的是一个抽象的Pet,不再面向具体的宠物
	//提倡:面向抽象编程,不要面向具体编程
	//面向抽象编程的好处:耦合度低、扩展力强
	public void feed(Pet pet){//Pet pet 是一个父类型的引用  Pet pet = new Cat(); | Pet pet = new Dog();
		pet.eat();
	}
}

/**
 * 多态在实际开发中的作用,以下以主人喂养宠物为例说明多态的作用:
 * 1、分析:主人喂养宠物这个场景要实现需要进行类型的抽象
 *      1)主人【类】
 *      2)主人可以喂养宠物,所以主人有喂养这个动作
 *      3)宠物【类】
 *      4)宠物可以吃东西,所以宠物有吃东西的这个动作
 * 2、面向对象编程的核心:定义好类,然后将类实例化为对象,给一个环境驱使一下,让各个对象之间协作起来形成一个系统。
 * 3、多态的作用是什么?
 *      降低程序的耦合度,提高程序的扩展力
 *      能使用多态尽量使用多态
 *      父类型引用指向子类型对象
 * 核心:提倡面向抽象编程,不要面向具体编程
 */
public class polymorphicTest02 {
	public static void main(String[] args) {
		//创建主人对象
		Master zhangsan = new Master();
		//创建猫对象
		Cat tom = new Cat();
		//主人喂养猫
		zhangsan.feed(tom);
		//创建小狗对象
	   // Dog erHa = new Dog();
		//zhangsan.feed(erHa);
		zhangsan.feed(new Dog());//父类型引用指向子类型对象、向下转型
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值