Java基础:面向对象特性(多态)

多态

多态表示事物的多种表现形态。在程序中,父类通常描述的是多个子类的共性,子类对象就可以作为一个有个性的父类出现,例如狗类可以作为动物类使用,猫类也可以作为动物来使用。

多态的表现需要在两个类存在继承关系的前提下,子类对象赋值给父类类型引用,例如:Animal a = new Dog();,这样的语法是对的,因为狗类可以称作是一个动物类。

可以结合基本类型的自动类型提升来描述多态,父类表示数据类型较大的变量,子类表示数据类型较小的值,使用较大变量接收较小的值是可以接受的。

多态可以屏蔽不同对象之间的差异,也就是说任何子类在经历多态之后都可以作为父类类型来使用。

构建多态

构建多态也就是将子类类型对象赋值给父类类型引用:

/*
		new Dog();//创建对象时,对象就已经拥有了类型。
		Dog d;//声明引用时,引用也拥有了相应的类型。
*/
Dog d = new Dog();//将Dog类型的对象,赋值给Dog类型的引用。
Animal a = new Dog();//将Dog(子类)类型的对象,赋值给Animal(父类)类型的引用。

多态的性质

  1. 对象在创建后,其类型就已经确定,无论放置在任何引用中,其对象的类型都不会改变。
  2. 在多态中,只能调用父类中生命过的方法。因为调用方法的是父类引用,父类是不可能获得子类的方法的。如果子类中存在父类中没有的方法,则在经过多态后并不能通过父类引用进行调用。
  3. 在调用时,实际调用的是子类对象中覆盖父类后的方法。

多态的应用

多态的应用实际借助了其“屏蔽不同对象之间的差异”这一作用,使任意子类对象都可以赋值到父类类型的引用中。

  1. 在方法返回值使用多态,可以返回多种类型的对象:

    public class Demo{
    	public static void main(String[] args){
    		FanShouJi fsj = new FanShouJi();
    		
    		//方法的返回值,并不是实际返回什么类型就是什么类型,
    		//而是方法声明的什么类型就是什么类型
    		ShiWu sw = fsj.getShangPin(2);
    		
    		//每个类中,默认存在getClass()方法,此方法用于获得此引用的对象的运行时类型
    		System.out.print(sw.getClass());
    	}
    }
    //当某一方法返回的数据类型是多种的,可以使用父类类型屏蔽它们的差异
    class FanShouJi{
    	public ShiWu getShangPin(int yingBi){
    		if(yingBi == 5){
    			return new Mian();
    		}else if(yingBi == 2){
    			return new Shui();
    		}else if(yingBi == 6){
    			return new BingGan();
    		}
    		//如果参数无法触发任何一个返回语句,则方法声明有误,需要至少返回一次
    		return null;
    	}
    }
    class ShiWu{}
    class BingGan extends ShiWu{}
    class Shui extends ShiWu{}
    class Mian extends ShiWu{}
    
  2. 在参数表中可以获得多种类型的对象:

    public class Demo{
    	public static void main(String[] args){
    		WuCan w = new WuCan();
    		w.chi(new XianCai());
    	}
    }
    
    class ShiWu{
    	public String weiDao(){
    		return "未知";
    	}
    }
    class XianCai extends ShiWu{
    	public String weiDao(){
    		return "咸";
    	}
    }
    class ManTou extends ShiWu{
    	public String weiDao(){
    		return "淡";
    	}
    }
    class XiFan extends ShiWu{
    	public String weiDao(){
    		return "甜";
    	}
    }
    
    class WuCan{
    	//在此方法上,接收的数据类型有多个,则使用其父类类型屏蔽不同对象之间的差异
    	//在实参对形参进行赋值的时候,就形成了多态
    	public void chi(ShiWu shiWu){
    		System.out.print(shiWu.weiDao());
    	}
    }
    
  3. 在数组中,可以存储多种类型的对象:

    public class Demo{
    	public static void main(String[] args){
    		DongWu zoo[] = {new Gou(),new Mao(),new Ji()};
    		
    		//数组中的元素的类型,并不是实际类型,而是数组声明的类型
    		DongWu dw = zoo[1];
    		System.out.print(dw.getClass());
    	}
    }
    
    class DongWu{}
    class Gou extends DongWu{}
    class Mao extends DongWu{}
    class Ji extends DongWu{}
    

对象类型的转换

对象类型的转换与基本类型的转换类似,也具有自动类型提升和强制类型转换。自动类型提升也就是将子类类型对象赋值到父类类型的引用中,也就是多态的过程。在经历多态之后的对象保存在父类类型中,如果要转换成原本类型就要经历强转。

如果经历多态,那引用就只能调用父类声明过的方法,但如果要调用子类中专有的方法,就要经历强转。

对象类型的强转

像基本类型类似,对象类型的强转也是通过小括号的方式进行,小括号中可以书写对象的本来类型或者父类类型:

Animal a = new Dog();
Dog d = (Dog)a;//Dog是子类类型,a是父类类型,使用子类类型引用接收父类类型引用中的内容需要强转!

进行强转时,如果对象类型与强转类型相同或者是对象类型的父类类型,则强转成功,否则将报错。例如强转的类型不是对象的直系父类,或者是对象的兄弟类或者子类,就会报错:

public class Test{
	public static void main(String[] args){
		ShengWu sw = new Gou();	//形成多态
		
		DongWu dw = (DongWu)sw;	//父类引用中存放的对象,是DongWu的子类,可以转换
		Gou g = (Gou)sw;		//父类引用中存放的对象,是Dog类,可以转换
		
		ZhiWu zw = (ZhiWu)sw;	//父类引用中存放的对象,是ZhiWu的侄子类,不可转换。
		Mao m = (Mao)sw;		//父类引用中存放的对象,是Mao的兄弟类,不可转换。
	}
}

class ShengWu{}

class DongWu extends ShengWu{}

class ZhiWu extends ShengWu{}

class Gou extends DongWu{}

class Mao extends DongWu{}
安全的类型强转

无论是对象类型还是基本类型,在强转时都会出现报错或者值溢出的情况。安全的强转指避免对象出现报错或者值溢出,通过检测的方式决定是否要进行转换,而不会改变值的内容。

基本类型转换较为简单,只要确定值能够存放到变量类型的空间里就可以:

int a = ?;

//先查看实际的内容是什么,再去进行转换!
//如果要对一个值,进行强转,就可以判断这个变量中的值,是否在byte能接受的范围之内。
if(a>=-128 && a<=127){
    byte b = (byte)a;
}

对象类型的转换分为两种方式,一种是采用引用中的getClass方法来确定对象的类型,如果与要进行强转的对象类型相同则可以进行转换:

//基本类型进行强转需要将其中的值进行判断
//对象类型的强转,是将对象类型进行判断(判断是否是本类,或者是否是子类(是否可以进行多态))

public class Test{
	public static void main(String[] args){
		ShengWu[] arr = {new Gou(),new Mao(),new DongWu(),new ZhiWu(),new ShengWu()};
		
		
		
		ShengWu sw = arr[1];
		
		//尝试着将sw转换成Mao类型
		
		//Mao m = (Mao)sw;//如果这样进行盲目强转,可能发生强转异常
		
		//借助着getClass方法"获得引用中对象的实际类型"
		
		//sw.getClass();//这句话就会获得sw的实际类型
		
		Mao m2 = new Mao();//这句话是获得一个确定好的真正的Mao对象
		
		if(sw.getClass() == m2.getClass()){//这句话是将不确定的sw对象,与确定的m2对象的类型进行匹配
			//如果sw的对象类型与m2的对象类型相同,则执行强转
			Mao m3 = (Mao)sw;
		}else{
			System.out.print("无法转换!");
		}
	}
}

class ShengWu{}

class DongWu extends ShengWu{}

class ZhiWu extends ShengWu{}

class Gou extends DongWu{}

class Mao extends DongWu{}

使用getClass的方式只能将对象转换为原本的类型,而不能转换为父类类型。而通过instanceof关键字进行判断,就可以将引用转换为当前类型或者其父类类型。语法为:boolean flag = 引用 instanceof 对象类型;,如果引用是对象类型或者对象类型的子类,语句则返回true,否则返回false:

public class Test{
	public static void main(String[] args){
		ShengWu[] arr = {new Gou(),new Mao(),new DongWu(),new ZhiWu(),new ShengWu()};
		
		
		
		ShengWu sw = arr[1];
		
		//在此处使用instanceof进行判断,Gou/Mao/DongWu都可以进行转换!
		//因为instanceof判断的是:引用是否是指定类型或者指定类型的子类。
		if(sw instanceof DongWu){
			DongWu m = (DongWu)sw;
		}else{
			System.out.print("强转失败!");
		}
	}
}

class ShengWu{}

class DongWu extends ShengWu{}

class ZhiWu extends ShengWu{}

class Gou extends DongWu{}

class Mao extends DongWu{}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值