多态 二

(三)协变返回类型

JavaSE5中添加了协变返回类型:在导出类中被覆盖的方法可以返回基类方法的返回类型的某种导出类型。
如下:

class Grain {
	public String toString() {
		return "Grain";
	}
}

class Wheat extends Grain {
	public String toString() {
		return "Wheat";
	}
}

class Mill {
	Grain process() {
		return new Grain();
	}
}

class WheatMill extends Mill {
	Wheat process() { // 协变。允许导出类的返回值的具体类型,不必强制覆盖。
		return new Wheat();
	}
}

public class CovariantReturn {
	public static void main(String[] args) {
		Mill m = new Mill();
		Grain g = m.process();
		System.out.println(g);
		m = new WheatMill();
		g = m.process();
		System.out.println(g);
	}
}

结果为:

Grain
Wheat

(四)用继承进行设计

注意:

  • 更好的方式是首先选择组合。更加灵活,可以动态的选择类型(也就是选择了行为),继承在编译时期就要知道确切的类型。
  • 一条通用准则:“用继承表示行为间的差异,并用字段表达状态上的变化”

如下:

class Actor {
	public void act() {
	}
}

class HappyActor extends Actor {
	public void act() { // 继承:表达act()方法的差异
		System.out.println("HappyActor");
	}
}

class SadActor extends Actor {
	public void act() {
		System.out.println("SadActor");
	}
}

class Stage {// 组合:使状态发生改变->行为的改变
	private Actor actor = new HappyActor();// 可以在运行时与另一个不同的对象绑定起来
//获得了动态灵活性(也被称为状态模式)
	public void change() {
		actor = new SadActor();
	}

	public void performance() {
		actor.act();
	}
}

public class Transmogrify {
	public static void main(String[] args) {
		Stage stage = new Stage();
		stage.performance();
		stage.change();
		stage.performance();
	}
}

结果为:

HappyActor
SadActor

1. 纯继承与扩展

注意:

  • is-a的关系。类的接口已经确定了它应该是什么,集成可以确保所有的导出类具有基类的接口,可以认为是一种“纯替代”。
  • 缺点:导出类中扩展的部分不能被基类访问,即:一旦上转型,则不能调用新方法。
  • 通常情况下,我们需要重新查明对象的确切类型,以便能够发访问类型所扩展的方法。

2. 向下转型与运行时类型的识别

注意:

  • 基类不会具有大于导出类的接口。
  • 在Java语言中,所有的转型都会得到检查。即使只是一次加括弧形式的类型转型,在运行期仍会检查。
  • 在运行期间进行检查的行为称作:运行时类型识别(RTTI)。
    如下:
class Useful {
	public void f() {
	}

	public void g() {
	}
}

class MoreUseful extends Useful {
	public void f() {
	}

	public void g() {
	}

	public void u() {
	}

	public void v() {
	}

	public void w() {
	}
}

public class RTTI {
	public static void main(String[] args) {
		Useful[] x = { new Useful(), new MoreUseful() };
		x[0].f();
		x[1].g();
		// 编译时,在Useful中没有被发现
		// x[1].u();
		((MoreUseful) x[1]).u();
		// ((MoreUseful) x[0]).u();

	}

}

(七)总结

  • 如果不运用数据抽象和继承,就不可能理解甚至创建多态的例子。
  • 多态是一种不能单独来看待的特性,需要与其他特性协同工作。
  • 为了有效的使用多态乃至面向对象技术,需要扩展编程视野,使其不仅包括个别类的成员和消息,而且还要包括类与类之间的共同特性以及它们之间的关系。
  • 尽管需要极大的努力,这样做是值得的。因为它可以带来很多成效,更快的程序开发过程,更好的代码组织,更好的扩展的程序以及更容易的代码维护。

猜你喜欢

转载自blog.csdn.net/qq_42349617/article/details/86310927