Java多态-----协变返回类型、状态模式、向下转型

这几天终于有自己的时间了,赶快更几篇博客,要多多学习新的知识呀,话不多说,进入正题……
协变返回类型

什么是协变返回类型?
子类被覆盖的方法可以返回基类类型的一个导出类型。
乍一看上去整个人都是懵的,之后看了好长时间才把这个意思弄明白,我先写段代码,之后好解释一点儿。

public class Test {
	public static void main (String [] args) {
		Owner o = new Owner();
		Pet p = o.myPet();
		System.out.println(p);
		o = new ManOwner();
		p = o.myPet();
		System.out.println(p);
	}
}
class Pet {
	public String toString() {
		return "this is a pet";
	}
}
class Cat extends Pet {
	public String toString() {
		return "this is a cat";
	}
}
class Owner {
	Pet myPet() {
		return new Pet();
	}
}
class ManOwner extends Owner {
	Cat myPet() {
		return new Cat();
	}
}

显示一下运行结果:

this is a pet
this is a cat

接下来进入我们刺激的肉眼跑代码流程:
1、Pet是父类,Cat是他的子类,子类重写父类当中的toString方法
2、Owner是父类,ManOwner是子类,子类中和父类有相同的方法myPet,但是返回类型不一样
3、主函数首先创建Owner类型的对象o,之后使用o创建Pet对象,最后调用p的toString方法(直接写p就是调用对象的toString方法),输出的肯定是this is a pet
4、之后使用o创建ManOwner对象,调用方法myPet创建Cat对象,赋值给引用p,那么p对应的toString方法输出的就是this is a cat,但是o的返回类型是Pet类型的,而且父类又使用不了子类的拓展方法,但是输出的结果证明返回的是Cat类型的数据。

这是为什么呢?
原来在jdk5之前,子类覆盖父类的方法签名都是需要完全一样的,但是在jdk5之后就放宽了这一约束,只要方法名相同或者子类方法的返回值是父类方法返回值的子类,那么就可以实现覆盖。

这样,前面的问题就解决了,myPet的方法名是相同的,所以第二次在对象o调用myPet方法的时候,绑定的方法是返回Cat类型的方法,输出结果也就是this is a cat

简单了解状态模式
什么是状态模式?
在程序运行的过程中,一个引用可以和不同的对象绑定起来,其行为也同时发生改变的,以便在运行时期得到动态灵活性,这种设计模式叫做状态模式。

下面还是拿一段代码来解释什么是状态模式。

public class Test {
	public static void main (String [] args) {
		Stage stage = new Stage();
		stage.perform();
		stage.change();
		stage.perform();
	}
}
//状态模式
class Actor {
	public void act() {	}
}
class HappyActor extends Actor {
	public void act() {
		System.out.println("happy action");
	}
}
class SadActor extends Actor {
	public void act() {
		System.out.println("sad action");
	}
}
class Stage {
	private Actor actor = new HappyActor();
	public void change() {
		actor = new SadActor();
	}
	public void perform() {
		actor.act();
	}
}

看看运行结果:

happy action
sad action

现在有一个舞台,上面有戏剧演员和悲剧演员,在舞台(stage)类当中有换场(change)的函数,当换场的时候把actor的绑定对象更改,就实现了运行时成员的状态,这就是状态模式

向下转型和运行类型识别

我们之前提到过向上转型,那个是把子类当做父类来用,是一种窄化的思想,但是向上转型会丢失信息,子类当中的扩展方法是没办法进行调用的,所以就出现了向下转型
向下转型是一种拓展的思想,通过向下移动(在继承的模式图当中,子类是在下面的)来获取类型的所有信息。

还是老规矩,用代码说话:

public class Test {
	public static void main (String [] args) {
		perform(new HappyActor());
	}
	public static void perform(Actor actor) {
		HappyActor hactor  = (HappyActor) actor;
		hactor.laugh();
	}
}
//状态模式
class Actor {
	public void act() {	}
}
class HappyActor extends Actor {
	public void act() {
		System.out.println("happy action");
	}
	public void laugh() {
		System.out.println("hiahiahia~");
	}
}

输出的结果是hiahiahia~
这就是向下转型,在perform方法当中,传进的对象都是Actor类型或者是其子类,在方法当中都转化为Actor类型,之后再**扮演(cast)**成一个HappyActor类型的对象,调用子类对象的扩展方法。
注意:在这里面是扮演,而不是强制转换,二者之间是有很大区别的。

这样虽然实现了访问子类所有信息,但是你必须保证转换的类型和参数传进来的对象是同一类型的,否则可能出现难以预料的结果。

我修改一下perform传进来参数看看。

public static void main (String [] args) {
		perform(new SadActor());
	}
	public static void perform(Actor actor) {
		HappyActor hactor  = (HappyActor) actor;
		hactor.laugh();
	}
}

我传进去的是SadActor类型的对象,但是后来扮演成了HappyActor类型的对象,悲剧演员变成喜剧演员了?这肯定不对呀。

所以说向下转型必须要保证转型的正确性。

这篇博客就写到这里了 ,希望对你的学习有帮助,记得点赞哦!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值