Java基础 面向对象的三大特征之多态

Java基础 面向对象的三大特征之多态

多态中的概念: 向上转型(upcasting) 子类–》父类,自动类型转换 向下转型(downcasting) 父类–》子类,强制类型转换 无论向上还是向下转型,两种类之间必须要有继承关系,没有继承关系编辑报错 多态的作用
  1. 降低程序的耦合度,提高扩展性
  2. 父类型引用指向子对象
  3. 面向抽象编程
一个动物类,动物类可以具有移动的方法,默认情况下继承Object:
// 动物类
public class Animal {
	public void move(){
		System.out.println("动物在移动");
	}
}
定义一个狗类Dog,继承动物类Animal:
public class Dog extends Animal{
	
	//重写Animal的move方法
	public void move(){
		System.out.println("狗在移动");
	}
}
定义一个Cat类,继承动物类Animal:
public class Cat extends Animal{
	//重写Animal的move方法
	public void move(){
		System.out.println("猫在移动");
	}
	
	// 猫独有的方法,抓老鼠
	public void CatchMouse(){
		System.out.println("猫在抓老鼠");
	}
}
创建一个测试类:
public class Test {
	public static void main(String[] args){
		
		Animal a = new Animal();
		
		Dog b = new Dog();
		b.move();
		b.eatBone();
		
		Cat c = new Cat();
		c.move();
	}
}
现在的结构是: Dog类继承Animal,但是在Dog类中有一个特有的eatBone方法 Cat类继承Animal,
public class Test {
	public static void main(String[] args){
		
		// 使用多态机制
		// Animal和Cat之间存在继承关系,Animal是父类,Dog是子类
		// new Dog()创建的对象类型是Dog,d这个引用的数据类型是Animal
		// 也就是发生了类型转换,子类型转换为父类型,称为向上转型,或者自动类型转换
		Animal d = new Dog();
		
		// java程序永远分为编译阶段和运行阶段
		// 编译无法通过,根本是无法运行
		// 编译阶段编译器会检测d这个引用的数据类型为Animal
		//Animal.class字节码当中有move方法,所以编译通过,这个过程称为静态绑定,编译阶段绑定
		
		//在程序运行阶段,JVM堆内存当中真实创建的对象是Dog对象
		//所以一定会调用Dog对象的move方法,此时发生了程序的动态绑定,运行阶段绑定
		d.move();//狗在移动
	}
}
父类型引用指向子类型对象这种机制导致程序会有编译阶段绑定和运行阶段绑定,两种不同的状态,这种机制可称为多态
public class Test {
	public static void main(String[] args){
		
		Animal d = new Dog();
		
		// 编译阶段编译器检测到d的类型是Animal
		// Animal.class字节码文件当中没有fly()方法
		// 导致静态绑定失败,编译失败
		d.fly();
	}
}
如果两种类型不村子啊任何继承关系,那么在编译阶段就会报错:
public class Test {
	public static void main(String[] args){
		
		Animal d = new Dog();
		// 编译报错,两种类型之间不存在任何继承关系,无法向上/向下转型
		Cat c = new Dog();
	}
}

现在我想让d引用调用Dog类中的eatBone方法,就目前的分析来看,是无法调用的,因为d的类型是Animal,Animal没有这个方法。这时候可以将d强制类型转换。d的类型是父类Animal,转换为Dog子类,称为向下转型/downcasting/强制类型转换

向下类型转换也需要两者存在继承关系,不然编译报错。强制转换需要加强制类型转换符
public class Test {
	public static void main(String[] args){
		
		Animal d = new Dog();
		// 强制类型转换
		
		Dog c = (Dog)d;
		c.eatBone();
	}
}
java.lang.ClassCastException异常
public class Test {
	public static void main(String[] args){
		
		Animal a = new Dog();
		// 强制类型转换
		// a的数据类型是Animal,Animal和Cat之间存在继承
		// 并且Animal是父类,Cat是子类
		// 父类型转换为子类型叫做向下转型,编译通过
		Cat b = (Cat)a;
		
		// 但是在运行阶段会出现异常
		// 因为JVM真实存在的对象是Dog,Dog对象无法转转为Cat对象
		// 两种类型之间不存在任何继承关系的
	}
}
向上转型:只要编译通过,运行一定不会出问题 向下转型:编译通过,运行可能错误,这时候可以使用instanceof运算符来解决报错,语法格式:
(引用 instanceof 数据类型的名)

// 执行结果为boolean类型,可能是true/false,例如

(a instanceof Animal)
true:
a引用指向的对象是一个Animal类型
false:
a引用指向的对象不是一个Animal类型
也就是我们在向下转型的时候,许哟啊采用这种方式:
public class Test {
	public static void main(String[] args){
		
		Animal a = new Dog();
		
		if(a instanceof Dog){ //a是一个Dog类型的对象
			Dog c = (Dog)a;
			c.eatBone();
		}else if (a instanceof Cat){//a是一个Cat类型的对象
			Cat c = (Cat)a;
			c.CatchMouse();
		}
	}
}
现在有一个主人类,多个宠物类,例如猫和狗,主人可以有这两个宠物:
public class Dog {
	public void eat(){
		System.out.println("狗在吃骨头");
	}

public class Cat {
	public void eat(){
		System.out.println("猫正在吃鱼");
	}
}
// 主人类
public class Master {
	// 面向具体的宠物
	public void feed(Cat a){
		a.eat();
	}
	
	public void feed(Dog a){
		a.eat();
	}
}
// 测试类
public class Test {
	public static void main(String[] args){
		//创建主人
		Master people = new Master();
		
		//创建猫
		Cat cat1 = new Cat();
		
		//主人喂猫
		people.feed(cat1);
		
		//创建狗
		Dog dog1 = new Dog();
		
		//狗吃骨头
		people.feed(dog1);
	}
}
现在主人还要养其它的宠物,那么需要重新创建一个宠物类,然后再主人类中修改代码,这就造成程序不宜维护,每次增加宠物都需要修改Master类,这时候就需要使用多态。创建一个宠物类:
public class Pets {
	public void eat(){
		
	}
}
让Dog类,Cat类继承Pets,如果有其他宠物,也应该继承Pets类,那么Maste类:
public class Master {
	//Master主人类面向的是一个抽象的Pets类,不再面向具体的宠物
	
	public void feed(Pets pet1){
		pet1.eat();
	}
}
public class Test {
	public static void main(String[] args){
		//创建主人
		Master people = new Master();
		
		//创建猫
		Cat cat1 = new Cat();
		
		//主人喂猫
		people.feed(cat1);
		
		//创建狗
		Dog dog1 = new Dog();
		
		//狗吃骨头
		people.feed(dog1);
	}
}
现在如果Maste类想继续养宠物,那么就不修改Master类,只需要添加额外宠物类即可!
分享到 :

发表评论

登录... 后才能评论