Java语言程序设计
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.2 面向对象程序设计

Java语言是一种面向对象(OO,Object Oriented)的程序设计语言。无论是Java应用程序还是Java小程序,它们都是以类为基础构建的。在认识Java程序前,这里先介绍一些关于面向对象程序设计的概念。

1.2.1 传统与面向对象程序设计语言

传统的面向过程的程序设计方法从解决问题的每一个步骤入手,较适合于解决规模较小的问题。如广为流传的传统程序设计语言BASⅠC、C等采用面向过程的程序设计模型,但是由于这类语言本身几乎没有支持代码重用的语言结构,并且缺乏统一的接口,使得当程序的规模达到一定程度时,程序员很难控制其复杂性。面向对象的程序设计方法则按照现实世界的特点来管理复杂的事物,把它们抽象为对象,具有自己的状态和行为,通过对消息的反应来完成一定的任务。

面向对象程序设计(OOP)是当今计算机领域最流行的程序设计方法。这里的“对象”是什么含义呢?借用一个现实世界中“车”的例子来说明对象的含义。

在现实生活中,人们理解的“车”有各种各样的种类,如手推车、自行车、摩托车、汽车等。从各种车可归纳出它们的共性,如车有车轮、重量、颜色等,是汽车还有车速、耗油量等。这些是从“车”这类事物抽象出来的共性,也即所谓的数据、数据成员或属性。车不仅有这些静态的数据,还有很多与这些数据有关的动作和行为,如车的启动、加速、刹车和修理等,这就是所谓的代码、成员函数或方法。将上述车的数据和动作代码组合起来,就得到一个车类(class)。

在Java语言中定义一个关于车的类,一般的形式为:

            class  车{ // 定义一个车类
              // 车的数据成员定义
              车轮数;
              车的颜色;
              车的重量;
              车速;
            ...
            // 车的成员方法定义
              启动();
              加速();
              刹车();
              修理();
              ...
            }

有了抽象的车类后,一辆实际的车,如一辆自行车、一辆汽车等,就是车类的一个对象(或称实例)。对象是一个实体,而不像车是一个抽象概念。类是一类事物共性的反映,而对象是一类事物中的一个,是个性的反映。每个对象都有与其他对象不完全一样的特性。如您和我的自行车虽然都是自行车,但二者的颜色、重量等就不可能完全一致。

通过抽象来处理复杂事物的方法可从现实世界对应到计算机程序设计中来。传统的算法程序可以抽象成各种要处理的对象,一个对象就是数据和相关的方法的集合,其中,数据表明对象的状态和属性,方法表明对象所具有的行为、操作和运算功能,即类和对象将需要处理的数据和对这些数据进行的各种操作封装起来,当需要的时候,就可以向对象发送消息,使得对象能够调用这些方法进行相应的动作。这就是面向对象编程的基础。与人类理解复杂事物的方式一样,面向对象的概念构成了Java语言的核心。

1.2.2 对象的性质

面向对象程序设计技术具有封装、继承、多态三个主要特性。

1.封装性

操纵汽车时,不用去考虑汽车内部各个零件如何运作的细节,而只需根据汽车可能的行为使用相应的方法即可。实际上,面向对象的程序设计实现了对象的封装,使用户不必关心对象的行为是如何实现这样一些细节的。从最基本的角度看,任何程序都包含两个部分:数据和代码。在传统的代码模型中,数据在内存中进行分配并由子程序或函数代码来处理。而面向对象设计的核心一环是将处理数据的代码、数据的声明和存储封装在一起。

可以把封装想像为一个将代码和数据包起来的保护膜。这个保护膜定义了对象的行为,并且保护代码和数据不被任何其他代码任意访问,即一个对象中的数据和代码相对于程序的其他部分是不可见的,它能防止那些不希望的交互和非法的访问。

Java封装的基本单元是类,即Java程序的基本元素是类。用户可以创建自己的类,它是一组具有行为和结构的对象的一种抽象。对象是相关类的具体实例,是将类作为模子造出的一个翻版。因此,有时也称对象为类的实例。

封装的目的是为了减少复杂性,因此,类具有一套隐藏复杂性的机制。类中的每个数据和方法可以被定义为公共或私有。类的公共部分可以让外界的用户知道或必须知道,公共的数据和方法是类与外部的接口,程序的其他部分通过这个接口使用类的功能。而定义成私有的数据和方法则不能被类以外的其他代码访问。

借助于类的封装性,便可以将数据和方法像部件一样用于各种程序,而不必了解和记忆其内部细节。改变类的其他部分不会对整个程序产生预料之外的影响,只要保持类接口不变,它的内部工作方式可以随意改动。

需要改变对象的数据或状态,或需要进行对象之间的交互时,面向对象的程序设计方法提供消息机制。例如,要使汽车加速,必须发给它一个消息,告诉它进行何种动作(这里是加速)以及实现这种动作所要的参数(这里是需要达到的速度等)。这里要指明消息的接收者、接收对象应采用的方法、方法所需要的参数。同时,接收消息的对象在执行相应的方法后,可能会给发送消息的对象返回一些信息(如加速后,汽车的车速表上会出现已经达到的速度等)。

由于任何一个对象的所有行为都可以用方法来描述,通过消息机制就可以完全实现对象之间的交互,同时,处于不同处理过程甚至不同主机的对象间都可以通过消息实现交互。

2.继承性

人们通常都会将世界看成相互关联的可划分层次的各种对象,如车、汽车和轿车。这里汽车是车的继承,而轿车又是汽车的继承。下一层次继承了上一层次的所有特性。一个多层次的继承关系构成了一个类树结构。

在已经定义了车类后,再定义一个汽车类,若再一次声明车轮数、颜色、重量等车类已定义的数据和方法,那么效率就太低了,其实只需定义汽车与一般意义下的车的不同即可。例如,增加定义一下汽车的车门数、座位数等,而继承车类中已定义过的数据和方法。这样可使得程序代码得到充分复用,结构更加清晰易懂,程序的可维护性、逻辑性就更强。

在面向对象的程序设计中,继承是指在已有类的基础上建立一个新类。新类自动拥有父类的所有元素:数据成员和成员方法,然后再根据需要添加新任务所需的数据成员和成员方法。合理使用继承可以减少很多的重复劳动。若类实现了一个特别的功能,那么由该类继承的新类(派生类)就可以重复使用这些功能,而不再需要重新编程。对Java的内置类可以创建派生类,也可以对自己创建的类建立派生类。

一个不由任何类派生的类称为基类;一个派生类的最近的上层类叫做该类的父类;从某一类派生出来的类叫做该类的子类。通过父类和子类,实现了类的层次,可以从最一般的类开始,逐步特殊化,定义一系列的子类。子类的层次并不是越多越好,因为,若层次太多,还不如重新创建一个新类。

一个类从派生它的基类到它自身可能要经过好几个层次。类不仅能继承其父类的所有方法和实例变量,而且还能继承从它的基类开始到它自身之间经过的所有层次上的类的方法和实例变量。通过继承也实现了代码的复用,使程序的复杂性线性地增长,而不是呈几何级数增长。

在Java中,继承车类派生汽车类的一般形式为:

              class汽车extends车 { ... }

继承和封装具有很好的合作性。若一个给定类封装了某些属性,那么它的任何子类将继承这些属性并可增加它们特有的属性。

3.多态性

不同的对象对于相同的方法表现其不同的理解和响应。可以想象的到:对于自行车和汽车,它们都能刹车,但它们的刹车方法却是完全不同的。

而在面向对象的程序设计语言中,多态性意味者一个对象具有多个面孔。Java通过方法重载(overload)和方法覆盖(override,也称为方法重写)来实现多态。

在一个类中声明多个名字相同但参数不同(个数或类型)的方法,称为方法重载。在子类中声明与父类中完全相同的方法称为方法覆盖。

通过方法覆盖,子类可以重新实现父类的某些方法,使其具有自己的特征。例如对于汽车类的加速方法,其子类(如赛车)中可能增加了一些新的部件来改善和提高加速性能,这时可以在赛车类中覆盖父类的加速方法。覆盖隐藏了父类的方法,使子类拥有自己的具体实现,更进一步表明了与父类相比,子类所具有的特殊性。

Java不仅允许程序设计者自己创建类,还针对各种应用提供了大量的预定义类库,例如屏幕显示、文件访问、数学计算等方面的类库。大量的预定义类的学习是Java语言学习的一个重点,也是一个难点。要掌握基本概念,通过对一些典型系统类的学习,学会举一反三,触类旁通。

有了有关类、对象的概念后,下面来看一看简单的Java程序。