Java 编程思想 6 (多态--同一消息导致不同行为)

摘要: 多态是面向对象令人惊叹的特性.

1. 什么是多态

多态是指同一消息导致不同的行为. 也就是说, 名义上使用了同一个方法调用, 而实际上执行了不同的实际方法.

2. 如何获得多态

多态通过覆盖获得.

2.1 通过继承

先生成一个 Doctor 类.

package thinking;

public class Doctor extends Human {
	/**
	 ********************* 
	 * Eat and grow.
	 ********************* 
	 */
	public void eat() {
		if (weight < 70000)
			weight += 15;
	}// Of eat

	/**
	 ********************* 
	 * The test method.
	 ********************* 
	 */
	public static void main(String args[]) {
		Human zhangsan = new Programmer();
		Human lisi = new Doctor();

		for (int i = 0; i < 10; i++) {
			zhangsan.eat();
			lisi.eat();
		} // Of for i

		System.out.println("The current weight of zhangsan is: " + zhangsan.weight);
		System.out.println("The current weight of lisi is: " + lisi.weight);
	}// Of main

}// Of class Doctor

本例可以看出, zhangsan 和 lisi 在变量声明的时候, 都是 Human. 但在实例化的时候, zhangsan 被实例化为 Programmer, 而 lisi 为 Doctor.

  • Programmer 并没有自己的 eat, 因此 zhangsan 按照人类的正常一般方式生长, 吃一次长 10 g, 10 次长了 100 g, 总质量 3100 g.
  • Doctor 实现了自己的 eat, 它对 Human 中的 eat 进行了 覆盖 overwrite, lisi 10 次长到 3150 g.

从这里我们可以看出:

  • 覆盖为同一方法产生了不同的版本, 因此它是获得多态的必要条件.
  • 在声明 Human 的时候, 实例化可以是 Human 或其任何子类. 找你要一个人, 你给了一个程序猿, 这没有任何问题. 但反之不行.

2.2 接口实现

我们把 Postman 扩充一下, 增加一个 main 方法.

package thinking;

public class Postman extends Human implements Messager{
	
	/**
	 ********************* 
	 * Implements the method of the interface.
	 ********************* 
	 */
	public void sendMessage(){
		System.out.println("I'm a postman sending message.");
		weight -= 50;
	}//Of sendMessage

	/**
	 ********************* 
	 * Test the class.
	 ********************* 
	 */
	public static void main(String args[]){
		Messager zhangsan = new Postman();
		Messager gugu = new Pigeon();
		
		zhangsan.sendMessage();
		gugu.sendMessage();
	}//Of main

} //Of class Postman

从这里可以看出:

  • 可以声明一个对象为一个接口, 如 Messager zhangsan.
  • 实例化时与类的原理相同.
  • 由于实现接口的类都必须写出相应的方法体, 自然就有方法的覆盖.

3. 多态还有什么神奇的事情

讲一个故事:
第 1 天, 你写了一个接口 Messager, 声明了sendMessage() 方法
第 2 天, 你写了 PostOffice 类, 它使用了 Messager 接口, 并调用了其 sendMessage() 方法.
第 3 天, 你写了 Postman 类, 实现了 sendMessage() 方法;
第 4 天, 你写了 MessageTest 类, 它生成了 PostOffice 的对象 tempOffice, 该对象利用类 Postman 的对象 zhangsan 送信.

package thinking;

public class PostOffice {

	/**
	 * The object is claimed as an interface.
	 */
	Messager myMessager;

	/**
	 ********************* 
	 * The default constructor.
	 ********************* 
	 */
	public PostOffice(Messager paraMessager) {
		myMessager = paraMessager;
	}// Of the constructor

	/**
	 ********************* 
	 * Send.
	 ********************* 
	 */
	public void send() {
		System.out.println("From a post office.");
		myMessager.sendMessage();
	}// Of send

}// Of class PostOffice

等等! 这里有点没对. 按照面向过程的思维, 后写的函数可以调用先写的函数. 但是, 第 2 天写的代码, 为什么能够调用第 3 天的代码? 它是如何做到未卜先知的?

从程序的角度, 编译时计算机看到 PostOffice 里面的语句

myMessager.sendMessage();

觉得没问题, 因为 sendMessage() 是 Messager 接口中定义好了的.
执行时, 计算机使用 Postman 里面的 sendMessage() 替换了接口中的方法, 所以完美地执行了任务.

Amazing ~

如果你熟悉人类社会的运作模式, 会觉得这个稀松平常: 老司机可以开新车, 虽然他从来没用这辆车练过手; 插座可以为新手机充电, 虽然它从来没用该手机测试过.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值