多态

利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。在7.3节中已经学习过子类对象可以被作为父类的对象实例使用,这种将子类对象视为父类对象的做法称为 “向上转型”。

假如现在要编写一个绘制图形的方法 draw(),如果传入正方形对象就绘制正方形,如果传入圆形对象就绘制圆形,这种场景可以使用重载来实现,定义如下:

public void draw(Square s) { // 绘制正方形的方法
}
public void draw(Circular c) { // 绘制圆形的方法
}

但是这种写法有个问题:正方形和圆形都是图形,这场景细分的重载方式不仅增加了代码量,还降低了 “易用度”。如果定义一个图形类,让它处理所有继承该类的对象,根据 “向上转型” 原则可以使每个继承图形类的对象作为 draw() 方法的参数,然后在 draw() 方法中做一些限定就可以根据不同图形类对象绘制相应的图形。这样处理能够很好地解决代码冗余问题,同时程序也易于维护。

【例7.12】万能的绘图方法(实例位置:资源包\TM\sl\7\12)

创建 Shape 图形类,作为 Square 正方形类和 Circular 圆形类的父类。创建 Demo6 类,并在该类中创建一个绘图用的 draw() 方法,参数为 Shape 类型,任何 Shape 类的子类对象都可以被作为方法的参数,并且方法会根据参数的类型绘制相应的图形。

class Shape { }								// 图形类

class Square extends Shape { }				// 正方形类继承图形类

class Circular extends Shape { }				// 圆形类继承图形类

public class Demo6 {
	public static void draw(Shape s) {			// 绘制方法
		if (s instanceof Square) {				// 如果是正方形
			System.out.println("绘制正方形");
		} else if (s instanceof Circular) {		// 如果是圆形
			System.out.println("绘制圆形");
		} else {							// 如果是其他类型
			System.out.println("绘制父类图形");
		}
	}

	public static void main(String[] args) {
		draw(new Shape());
		draw(new Square());
		draw(new Circular());
	}
}

运行结果如下:

     绘制父类图形
     绘制正方形
     绘制圆形

从本实例的运行结果中可以看出,以不同类对象为参数调用 draw() 方法,可以处理不同的图形绘制问题。使用多态节省了开发和维护时间,因为程序员无须在所有的子类中定义执行相同功能的方法,避免了大量重复代码的编写。同时,只要实例化一个继承父类的子类对象,即可调用相应的方法,如果需求发生了变更,只需要维护一个 draw() 方法即可。

编程训练(答案位置:资源包\TM\sl\7\编程训练)

【训练13】教师与学生 使用多态编写一个程序,在控制台上输出如下内容。其中,人类(People)既是教师类(Teacher)的父类,也是学生类(Student)的父类。

     每个人都要工作
     教师要认真授课
     学生要好好学习

【训练14】交通灯亮几秒? 使用instanceof关键字模拟交通红绿灯的点亮时间,控制台输出如下内容:

     红灯亮45秒
     黄灯亮5秒
     绿灯亮30秒