1.5 面向对象编程的关键特性
Java的核心在于面向对象编程(Object-Oriented Programming,OOP)。面向对象的方法学是Java不可或缺的一部分。所有的Java程序或多或少都是面向对象的。因为面向对象对Java如此重要,甚至在写一个简单的Java程序前了解面向对象的基本原则都是有用的。
面向对象是解决编程工作的一个强有力的方法。自从计算机发明以来,编程方法学有着很大的变化,这些变化主要是为了适应不断增长的编程复杂度。例如,在计算机刚发明时,编程是通过计算机的前面板(front panel)以二进制机器指令的方式输入的。由于程序只有几百个指令,这种方法还可行。随着程序长度的增加,汇编语言应运而生。程序员可以使用机器指令的符号表示,来处理更大的、更复杂的程序。第一种广泛流行的语言是FORTRAN。经过这是非常引人注目的一步,但是大型的FORTRAN程序还是相当难以理解。
20世纪90年代,结构化编程诞生了。这是C和Pascal推崇的方法。结构化语言的使用使得编写适当复杂的程序变得相当容易。结构化语言的特点有:独立的子例程、局部变量、丰富的控制结构、不依赖于GOTO语句。尽管结构化语言是一个强有力的工具,它们也会遇到瓶颈。
不妨这么考虑:在编程发展的各个关键节点,技术和工具的发明使得程序员能够处理更大的复杂度。在语言演进的道路上,新的方法都攫取前人的最好元素,并再向前改良。在面向对象编程发明之前,许多项目都几乎接近(甚至已经)崩溃。面向对象的方法能够帮助程序员克服这些障碍。
面向对象编程汲取了结构化编程中最优秀的思想,将其与一些新的概念结合。这产生了一种组织程序的不同方法。一般认为,程序可以用以下两种方法中的一种进行组织:围绕代码(即发生的动作)进行组织,或围绕数据(即受影响的内容)进行组织。若只用结构化编程技术,程序一般围绕代码组织。这种方法可以认为是“代码操作数据”的思想。
面向对象编程使用另一种方法。它围绕数据进行组织,它的关键原则是:数据控制代码的访问权限。在面向对象语言中,可以定义数据和运行操作数据的子例程。于是,数据类型精确定义了什么类型的操作可以应用于这个数据。
为了支持面向对象编程的原则,所有面向对象的语言(包括Java)有三种特性:封装、多态和继承。让我们对此逐一考查。
1.5.1 封装
封装(encapsulation)是一种编程技术,它将代码与其操作的数据绑定起来,使它们在有外界的干扰和误用的情况下保持安全。在面向对象语言中,代码和数据可以以一种自包含的黑盒(black box)的方式绑定。在这个黑盒内,有所有必需的数据和代码。当代码和数据以这种方式联系起来时,对象就诞生了。换句话说,对象是支持封装的设备。
在对象内部,对对象而言,代码、数据或两者都有可能是私有的(private)或公有的(public)。只有对象其他部分才能解和访问私有代码和数据。也就是说,对象外部存在的程序片段不能访问私有代码和数据。当代码或数据是公有的时,即使它们定义在对象内部,程序的其他部分能够访问到它们。一般情况下,对象的公有部分用来提供针对对象私有元素的控制接口。
Java封装的基本单元是类(class)。尽管在本书后文将对类进行详细介绍,但在此进行一些简单介绍也是有益的。类定义了对象的形式。它指定了数据和操作数据的代码。Java使用类的描述来构造对象(object)。对象是类的实例(instance)。所以,类在本质上是一个规划集合,这个集合指定创建对象的方式。
组成的代码和数据称为类的成员(member)。特别是,类中的数据称为成员变量(member variable)或实例变量(instance variable)。操作数据的代码称为成员方法(member method),或简称方法(method)。
1.5.2 多态
多态(polymorphism)这个词起源于希腊语,是“多种形态”的意思。多态这个性质允许我们仅通过一个接口来访问一类动作。而具体执行哪些动作由当时具体的情形决定。汽车的方向盘就是多态的一个简单例子。无论实际使用哪种方向盘,方向盘(也就是接口)都是一样的。即,无论汽车采用手动操作还是电动操作的方向盘,方向盘都同样工作。于是,一旦了解如何操作方向盘,就可以驾驶任意种类的汽车,而不用关心方向盘是如何实现的。
这个原则对编程也同样适用。下面就举一个简单的例子。比如创建一个接口,它定义一个称为get的操作,用从某种表单中获得下一项数据。这种获取下一项数据的动作,基于数据的存储方式,可以有很多实现方式。例如,数据项可能是以先进先出的顺序存储的,也可能是以先进后出的顺序存储的,或是以某种优先级存储的,还可能以许多其他方式存储。但是,只要某种存储机制实现了这个接口,用户就可以通过get方法来检索下一数据项。
更一般地,多态的概念可以表述为“一个接口,多种方法”。这意味着,有可能为一组相关的活动设计一个通用的接口。多态通过允许为一般动作使用同一接口来降低复杂度。而编译器会为每个应用场景选择特定的动作(即方法)。程序员无须手动做出选择,只须使用通用接口即可。
1.5.3 继承
继承(inheritance)是一个对象从另一个对象获取属性的过程。由于它支持按层级结构分类的概念,因此它非常重要。实际上世间绝大部分知识都是以按层次结构(即自顶向下)的分类管理的。例如,红富士苹果是苹果的一种,而苹果又是水果的一种,而水果又是食物的一种。换句话说,食物的所有品质(如可食用性、有营养等)都适用于水果;水果还有其独有的特征(如多汁、味甜等)。水果的独有特征使其与其他食物分离开来。苹果也定义了其独有的品质(如长在树上、非热带作物等)。依次地,红富士苹果也继承了前述大类的品质,还定义了一些使其独一无二的品质。
如果不使用继承,每个对象就只能显式定义所有特点。使用继承,对象只需在类中定义使其独一无二的品质。它能从其父类继承一般特性。于是,继承机制使得从一个更一般的情况来定义一个特别的实例对象成为可能。