三大特性之多态

  • 概念:父类引用可以存储不同的子类对象,子类对象不同呈现出不同的状态,固称为多态。
  • 在程序中的体现:
package com.txw.test;
import java.util.Scanner;
public class TestPolymorphism{
	public static void main(String[]args){
		Animal d = new Dog();
		// 使用的属性与方法,都是由对象负责存储或调用的
		d.name = "森森";
		d.eat();		// 调用覆盖后的方法
		d.sleep();	// 调用父类的
		/*
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		Animal a1 = null;
		// 编译时不能确定a1所存储的对象
		if( n==1 )
			a1 = new Dog();
		else
			a1 = new Fish();
		// 所有Animal子类对象都具备eat,sleep可以调用
		a1.eat();
		a1.sleep();
		*/
		// 不是所有对象都具备swim,shout,run方法
		// a1.swim();
		// a1.shout();
		// a1.run();		
		// 强类型语言,数据类型与变量类型 必须一致
		
		//父类引用   子类对象
		// Animal a1 = new Dog();
		// Animal a2 = new Cat();
		// Animal a3 = new Fish();
		// Animal a4 = new Bird();
		
		// Worker not is a  Animal 
		// Animal a5 = new Worker(); Error
		
		// Dog d = new Dog();	// 创建Dog对象
		// Pet p = d;
		// Animal a = d;
		// System.out.println( d );
		// System.out.println( p );
		// System.out.println( a );
	}
}
class Worker{}
class Animal{
	String name;
	int age;
	public void eat(){
		System.out.println("eat() in Animal ");
	}
	public void sleep(){
		System.out.println("sleep() in Animal ");
	}
}
class Pet extends Animal{}		// 宠物 is a 动物

// 在程序中说明 Dog is a Pet
class Dog extends Pet{
	// 覆盖父类中的方法
	public void eat(){
		System.out.println("eat() in Dog ");
	}
	public void swim(){}
	public void shout(){}
	public void run(){}
}
class Cat extends Animal{
	public void shout(){}
	public void run(){}
}
class Fish extends Animal{
	public void swim(){}
}
class Bird extends Animal{
	public void shout(){}
	public void fly(){}
}

在父类引用中存储子类对象。

1 多态的特点

1.1对象类型始终不变

演示的代码如下:

class Animal{}
class Pet extends Animal{}		// 宠物 is a 动物
class Dog extends Pet{}			// 狗 is a 宠物

Dog d = new Dog(); // 创建Dog对象
Pet p = d;
Animal a = d;
System.out.println( d );		// classes.Dog@15db9742
System.out.println( p );		// classes.Dog@15db9742
System.out.println( a );		// classes.Dog@15db9742
1.2 编译时只能调用引用类型中的方法

演示的代码如下:

Scanner sc = new Scanner(System.in);
int n = sc.nextInt();  		
Animal a1 = null;
// 编译时不能确定a1所存储的对象
if( n==1 )
	a1 = new Dog();
else
	a1 = new Fish();
// 所有Animal子类对象都具备eat,sleep可以调用
a1.eat();
a1.sleep();  		
// 不是所有对象都具备swim,shout,run方法
// a1.swim();
// a1.shout();
// a1.run();
1.3 如果子类覆盖了父类的方法,执行覆盖后的方法

演示的代码如下:

Animal d = new Dog();
// 使用的属性与方法,都是由对象负责存储或调用的
d.name = "森森";
d.eat();		// 调用覆盖后的方法 打印 eat() in Dog
d.sleep();		// 调用父类的    打印 sleep() in Animal 

class Animal{
	public void eat(){
		System.out.println("eat() in Animal ");
	}
	public void sleep(){
		System.out.println("sleep() in Animal ");
	}
}
// 在程序中说明 Dog is a Animal
class Dog extends Animal{
	// 覆盖父类中的方法
	public void eat(){
		System.out.println("eat() in Dog ");
	}
	public void swim(){}
	public void shout(){}
	public void run(){}
}

2 向下转型

  • 作用:
    由于多态存在,父类引用中存储子类对象,只能调用引用类型(父类)中的方法,如果需要使用子类中的方法,必须将引用类型转换为子类,由父类引用转换为子类引用称为向下转型。
    
    演示的代码如下:
package com.txw.test;
public class TestPoly{
	public static void main(String[]args){
		
		Animal a = new Dog();
		// 只能调用引用类型中的方法
		a.eat();
		a.sleep();
		// 调用子类中的方法,必须更换引用类型
		// 将父类的引用转换为子类引用(向下转型)
		if(a instanceof Dog){
			Dog d =(Dog)a;		// 将a引用中存储的对象付给d引用
			d.swim();
			d.shout();
			d.run();
		}
		System.out.println("程序结束");
		// 强制类型转换有可以会出现
		// java.lang.ClassCastException:类型转换异常 classes.Cat cannot be cast to classes.Dog
	}
}
class Animal{
	String name;
	int age;
	public void eat(){
		System.out.println("eat() in Animal ");
	}
	public void sleep(){
		System.out.println("sleep() in Animal ");
	}
}
// 在程序中说明 Dog is a Pet
class Dog extends Animal{
	// 覆盖父类中的方法
	public void eat(){
		System.out.println("eat() in Dog ");
	}
	public void swim(){System.out.println("swim() in Dog");}
	public void shout(){}
	public void run(){}
}
class Cat extends Animal{
	public void shout(){}
	public void run(){}
}
class Fish extends Animal{
	public void swim(){}
}
class Bird extends Animal{
	public void shout(){}
	public void fly(){}
}

注意:

由于引用类型为父类型可以存储任意类型子类对象,所以向下转型时可能失败。
比如:
Animal a = new Dog();
Cat c = a;
编译时编译器认为类型转换可能会出现问题,所以出现编译错误。
  • 强制类型转换(拒绝编译器干预)
    语法如下:

    引用类型 引用名 =(类名) 引用;
    

    比如:

    Animal a = new Dog();
    Dog d =(Dog) a;	// 将Animal类型的引用a,强制类型转换为Dog类型引用d(向下转型)
    

    编译器不再干预转换过程,如果运行时对象类型与引用类型不兼容,则出现: 类型装换异常 java.lang.ClassCastException:类型转换异常

  • 向下转型后即可使用子类引用访问子类对象中的方法。

      Animal a = new Dog();
      // 只能调用引用类型中的方法
      a.eat();
      a.sleep();
      // 调用子类中的方法,必须更换引用类型
      // 将父类的引用转换为子类引用(向下转型)
      Dog d =(Dog)a;//将a引用中存储的对象付给d引用
      // 使用子类引用访问子类对象中的方法
      d.swim();
      d.shout();
      d.run();
    

3 instanceof 关键字

  • 作用:用于判断引用类型中存储的对象是否与某种类型兼容。
    语法如下:
    引用名 instanceof 类名  。
    结果为boolean,兼容返回true,不兼容返回 false
  • 应用场景:
  1. 找出某种类型的对象。
package com.txw.test;
public class TestAnimalArray{
	public static void main(String[]args){
		int i1 = 1;
		int i2 = 200;
		int i3 = 400;
		int[] is = {i1,i2,i3};
		
		for(int i=0; i<is.length; i++){
			// 从数组中提取数据
			int x = is[i];
		}		
		Animal a1 = new Dog();
		Animal a2 = new Cat();
		Animal a3 = new Fish();
		Animal a4 = new Bird();
		Animal a5 = new Cat();
		Animal a6 = new Fish();
		Animal a7 = new Dog();
		// 对象数组,
		Animal[] as = {a1,a2,a3,a4,a5,a6,a7};
		// 统计Dog对象的数量
		int count = 0;
		// 遍历数组
		for(int i=0; i<as.length; i++){
			// 从数组中提取数据
			Animal a = as[i];
			// 判断如果a引用中存储的对象为Dog类型
			if(a instanceof Dog){
				System.out.println( a );
				count++;
			}
		}
		System.out.println(count);
	}
}
  1. 强制类型前进行判断,避免类型转换异常的发生
    演示的代码如下:
    Animal a = new ?();
    // 只能调用引用类型中的方法
    a.eat();
    a.sleep();     
    // 将父类的引用转换为子类引用(向下转型)
    // a instanceof Dog:判断a引用中存储的对象是否与Dog类型兼容
    if(a instanceof Dog){
    	Dog d =(Dog)a;	// 将a引用中存储的对象付给d引用
    	d.swim();
    	d.shout();
    	d.run();
    }
    

4 多态的应用场景

  • 多态的作用:父类引用类型屏蔽子类类型之间的差异。
    演示1:自动贩卖机。
package com.txw.test;

import java.util.Scanner;
public class Test{
    public static void main(String[]args){
        System.out.println("===欢迎使用阿森自动售货机===");
        System.out.println("请输入商品编号:");
        System.out.println("1:红牛");
        System.out.println("2:奶茶");
        System.out.println("3:可乐");
        System.out.println("4:冰红茶");
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();

        // 创建自动售货机对象
        VendingMachine vm = new VendingMachine();
        Beverage rb= vm.sell( n );		// 调用贩卖方法,传入商品编号
        System.out.println("您购买了"+rb.name+"饮料,花费:"+rb.price);
    }
}
// 自动售货机
class VendingMachine{
    // 贩卖方法,int n表示商品编号
    public Beverage sell(int n){
        switch( n ){
            case 1 : Beverage rb = new RedBull("红牛维生素饮料",6D);	// 创建红牛对象
                return rb;
            case 2 : Beverage mt = new MilkTea("优乐美奶茶",5D);
                return mt;
            case 3 : Beverage co = new Cola("可口可乐",3D);
                return co;
            case 4 : Beverage ibt = new IceBlackTea("康师傅冰红茶",3D);
                return ibt;
            default:System.out.println("没有该类商品!");return null;
        }
    }
}
// 饮料
class Beverage{
    String name;
    double price;
    public Beverage(){}
    public Beverage(String name,double price){
        this.name = name;
        this.price = price;
    }
}
// 红牛
// 红牛 is a 饮料
class RedBull extends Beverage{
    public RedBull(){}
    public RedBull(String name,double price){
        super(name,price);
    }
}
// 奶茶
// 奶茶 is a 饮料
class MilkTea extends Beverage{
    public MilkTea(){}
    public MilkTea(String name,double price){
        super(name,price);
    }
}
// 可乐
// 可乐 is a 饮料
class Cola extends Beverage{
    public Cola(){}
    public Cola(String name,double price){
        super(name,price);
    }
}
// 冰红茶
// 冰红茶 is a 饮料
class IceBlackTea extends Beverage{
    public IceBlackTea(){}
    public IceBlackTea(String name,double price){
        super(name,price);
    }
}

演示2:士兵作战。

package com.txw.test;
public class TestSoldier{
  public static void main(String[]args){		
  	Fiream f1 = new Rifle("AK-47","7.62mm");
  	Fiream f2 = new Rifle("M4A1","5.56mm");
  	Fiream f3 = new Snipe("AWM","马格南");
  	Fiream f4 = new Snipe("Bletter","8.53mm");
  	Fiream f5 = new Shoutgun("S12K","12mm");
  	Fiream f6 = new Shoutgun("DBS12","12mm");		
  	Fiream[] fs = {f1,f2,f3,f4,f5,f6};		
  	
  	Soldier s = new Soldier("阿森",18);		
  	for(int i=0; i<fs.length; i++){
  		s.attack( fs[i] );
  	}
  }
}
// 士兵
class Soldier{
  String name;
  int age;
  public Soldier(){}
  public Soldier(String name,int age){
  	this.name = name;
  	this.age =  age;
  }	
  // 攻击敌人
  public void attack(Fiream f){
  	System.out.print(name+"\t"+age);
  	System.out.println(" 士兵正在使用 "+f.name+" 攻击敌人");
  	f.fire(); // 使用武器开火
  }
}
// 枪械类
abstract class Fiream{
  String name;
  String ammo;
  public Fiream(){}
  public Fiream(String name,String ammo){
  	this.name = name;
  	this.ammo = ammo;
  }
  public abstract void fire();
}
// 步枪
class Rifle extends Fiream{
  public Rifle(){}
  public Rifle(String name,String ammo){
  	super(name,ammo);
  }
  public void fire(){//开火
  	System.out.println("dadadadadada~~~~~");
  }
}	
//狙击枪
class Snipe extends Fiream{
  public Snipe(){}
  public Snipe(String name,String ammo){
  	super(name,ammo);
  }
  public void fire(){
  	System.out.println("duang~~~~~~~");
  }
}	
// 散弹枪 霰弹枪
class Shoutgun extends Fiream{
  public Shoutgun(){}
  public Shoutgun(String name,String ammo){
  	super(name,ammo);
  }
  public void fire(){
  	System.out.println("peng~~~~peng~~~~~peng~~~~~");
  }
}

总结如图所示:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学无止路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值