8.1.2 面向对象的基本概念
(1)对象(object)。对象是客观存在,要研究的事和物。可以是人为的概念,也可以是任何有明确边界和意义的物品。例如:一名学生、一家公司、一本图书、借书、还书等,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。对象由数据(描述事物的属性)和作用于数据的操作(体现事物的行为)构成一独立整体。从程序设计者来看,对象是一个程序模块,从用户来看,对象为他们提供所希望的行为。总之,对象是问题域中某个实体的抽象,设立某个对象就反映了软件系统保存有关它的信息并具有与它进行交互的能力。
由于客观世界中的实体通常都既具有静态的属性,又具有动态的行为,因此,面向对象方法学中的对象是由描述该对象静态属性的数据与描述该对象动态行为的操作封装在一起构成的统一体。一个对象通常由对象名、属性和操作三个部分组成。
使用对象时,需要注意以下六点。
①对象是数据封装起来的,对数据的处理需要通过特定的操作。
②对象之间通过传递消息进行通信,不同的对象独立地处理自身的数据。
③要处理对象的内部数据时,外界需要通过接口向对象发送消息,请求执行特定的操作。
④对象具有状态,一个对象用数据值来描述它的状态。
⑤对象还有操作,用于改变对象的状态,操作就是对象的行为。
⑥对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中。
(2)类(class)。在面向对象技术中,“类”就是对具有相同属性和相同操作的一组相似对象的集合。也就是说,类是对具有相同属性和行为的一个或多个对象的描述。
有相同或相似性质的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象。例如,张三、李四、王五等。虽说每个人职业、性格、爱好、特长等各有不同,但是,他们的基本特征是相似的,都是黄皮肤、黑头发、黑眼睛,于是人们把他们统称为“中国人”。人类习惯于把有相似特征的事物归为一类,分类是人类认识客观世界的基本方法。
类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。
类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。
谈到类的概念,就必须知道什么是类的实例。实例是由某个特定的类描述的一个具体的对象。
如图8.1所示,“学生”是一个类,“学生”类的实例“张同学”“李同学”等都是对象。类是一个支持继承的抽象数据类型,而对象就是类的实例,类和对象的关系类似于程序设计语言中的数据类型和变量之间的关系。

图8.1 类及实例
(3)消息(Message)。软件对象通过相互间传递消息来相互作用和通信。消息,就是要求某个对象执行在定义它的那个类中所定义的某个操作的规格说明。通常一个消息由下述三个部分组成。
①对象名:接收消息的对象。
②消息名:要求接收对象完成的操作。
③参数:执行操作时的参数或者操作返回的结果。
例8.1 student1是学号为10001,姓名为张同学,年龄为20岁的学生类的对象,也就是学生类的一个实例,下面是张同学发送的一条消息:
student1.set(Number)。(https://www.daowen.com)
其中,student1是接收消息的对象名称,set是要求对象执行的操作名称,圆括号内的Number是消息的操作参数。当student1对象接收到这个消息后,将执行在学生类中所定义的set操作。
(4)方法(Method)。方法,就是对象所能执行的操作,也就是类中所定义的服务。方法描述了对象执行操作的算法和响应消息的方法。对象之间进行通信的结构叫作消息。在对象的操作中,当一个消息发送给某个对象时,消息包含接收对象去执行某种操作的信息。发送一条消息至少要包括说明接收消息的对象名、发送给该对象的消息名(即对象名、方法名)。一般还要对参数加以说明,参数可以是认识该消息的对象所知道的变量名,或者是所有对象都知道的全局变量名。在面向对象程序语言中把方法称为成员函数。
类中操作的实现过程叫作方法,一个方法有方法名、返回值、参数、方法体。
例如,学生类提供了void set(String)方法,该方法也就是学生类的成员函数。由学生类派生出来的对象,张同学,李同学都可以执行set操作,并实现相应的动作。
(5)属性(Attribute)。属性,就是类中所定义的数据,是对客观世界实体所具有的性质的抽象。类的每个实例都有自己特有的属性值。在面向对象程序语言中把属性称为数据成员。
例如学号、姓名、年龄等信息都为学生类的数据成员,而每个对象可以有不同的属性值。张同学各属性的取值分别为“10001,张同学,20”,李同学各属性的取值可以是“10002,李同学,22”。
(6)封装(Encapsulation)。封装性是保证软件部件具有优良的模块性的基础。
面向对象的类是封装良好的模块,类定义将其说明(用户可见的外部接口)与实现(用户不可见的内部实现)显式地分开,其内部实现按其具体定义的作用域提供保护。
对象是封装的最基本单位。封装防止了程序相互依赖性而带来的变动影响。面向对象的封装比传统语言的封装更为清晰、更为有力。
使用一个对象的时候,只需要知道他向外界提供的接口形式而无须知道它的数据结构细节和实现操作的算法。
实现封装性的条件如下。
①有一个清晰的边界。所有私有数据和实现操作的代码都被封装在这个边界内,从外面看不见更不能直接访问。
②有确定的接口(即协议)。这些接口就是对象可以接收的消息,只能通过向对象发送消息来使用它。
③受保护的内部实现。实现对象功能的细节(私有数据和代码)不能在定义该对象的类的范围外进行访问。
封装性也就是信息隐藏,通过封装把对象的实现细节对外界隐藏起来了。
(7)继承(Inheritance)。继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。继承性是面向对象程序设计语言不同于其他语言的最重要的特点。
一个类可以定义为另一个更一般的类的特殊情况,如“轿车”类是“汽车”类的特殊情况,这时可以称一般类是特殊类的父类,特殊类是一般类的子类。如“汽车”类是“轿车”类的父类,“轿车”类是“汽车”类的子类。同样“汽车”类还可以是“交通工具”类的子类,“交通工具”类是“汽车”类的父类。这样可以形成类的一般到特殊的层次关系,如图8.2所示。

图8.2 一般特殊关系
在这一般到特殊的关系,子类可以继承其父类的所有属性和操作,子类中还可以定义自己特有的属性和操作。所有子类的属性和操作是子类中的定义部分和父类中的定义部分的总和。
继承是类间的一种基本关系,是基于层次关系的不同类共享数据和操作的一种机制。父类中定义了其所有子类的公共属性和操作,在子类中除了定义自己特有的属性和操作外,还可以重新定义父类中操作的实现方法,称为重载(override)。例如,根据学生类定义子类大学生类,在学生类中定义了属性学号、姓名、年龄等;定义了操作set方法等。在大学生类中,可定义自己的学分,还可以对操作set方法重新定义。
(8)多态性(Polymorphism)。多态性是指相同的操作、函数或过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。例如,“set”操作,作用在“学生”对象上,设置的是学生的学号信息,而作用在“大学生”对象上,则可以重写为设置大学生学分信息。也就是说,相同操作的消息发送给不同对象时,每个对象将根据自己所属类中定义的这个操作去执行,从而产生不同的结果。
(9)重载(Overloading)。有两种重载:函数重载是指同一作用域内的若干个参数特征不同的函数可以使用相同的函数名字;运算符重载是指同一个运算符可以施加于不同类型的操作数上。当然,当参数特征不同或被操作数的类型不同时,实现函数的算法或运算符的语义是不同的。重载进一步提高了面向对象系统的灵活性和可读性。