2.3 对象和类的初步知识

对象是Java程序的基本构造元件,因此Java程序设计过程中必须识别所包含的对象。类是对象的定义模板,是对象的抽象描述。类采用包的结构进行组织。对象是在程序运行过程中创建和使用的。

2.3.1 对象概述

在针对程序需要解决的问题的应用程序开发过程中,所有有关的需要概念化或模型化的元素都可以抽象为对象。这些元素可以是问题空间中的有关物理实体,也可以是程序解题过程中人为添加的概念化元素,或是与问题相关联的任何东西。程序中任何一个设计良好的对象都为解题提供服务,完成一项程序任务。

对象是程序中的一个自包含构件,包含它所表示的元素的内部状态——该元素有关属性的当前值,以及对其所表示元素的操作——获取、使用和修改该元素有关属性值。对象的状态改变必须通过该对象的操作完成。其他对象要获取或改变该对象的状态,只需向该对象发出请求——发送消息,由该对象自身完成所请求的操作。

采用面向对象程序设计方法开发程序,首先要识别出解题任务中的对象。一般方法是在对问题进行细致分析的基础上,整理出想让系统完成的具体任务,并写出较为细致具体的描述问题和任务的文档。然后在描述文档中查找名词,这些名词有可能就可以作为程序中的对象。

例如,2.1节中的简单加法计算器程序中可能的对象包括计算器、加数、被加数、和数。此外,要求程序采用图形用户界面,那就可能还有程序窗口对象、显示和存放运算数据的三个文本字段对象、三个描述性标签对象及两个操作按钮对象。

2.3.2 类概述

面向对象程序设计世界中存在着大量的相似对象。例如,每个程序都至少有一个窗口对象,它们都有位置、大小等属性,都具有改变大小、移动位置、最大化、最小化和关闭等操作。在2.1节简单加法计算器程序项目中单击编辑窗口上部的“设计”按钮,切换到设计视图,分别右键单击三个文本字段对象,选择快捷菜单中的“属性”菜单项,在弹出的“属性”窗口中看到它们具有大量的共同属性(见图2.14)。在“源”代码窗口,紧接三个文本字段对象名(jTextFieldNum1、jTextFieldNum2、jTextFieldResult)的后面输入句点“.”,在弹出的方法提示框中拖动右边的滚动条,可以看到都有获取所显示文字、设置文字等大量的共同操作(见图2.15)。分类是人们认识世界的一种基本方法,将相似的对象归为一类可以简化编程。

在面向对象程序设计中,类是具有共同属性和操作的一组相似对象的定义,类在程序中用来描述一组对象的共同属性和操作。在程序设计中,类就是创建对象的模板。

Java语言使用class关键字定义一个类,紧接该关键字之后为该类取一个类名字,然后在一对大括号(“{}”)中定义类体。即类的定义具有以下形式。

图2.14 简单加法计算器程序中的三个文本字段属性比较

图2.15 简单加法计算器程序中的三个文本字段方法比较

     [修饰符] class 类名 [其他限定] {
         // 属性定义,若干行语句,定义一些变量
         // 方法定义,若干个程序块,定义程序所能执行的操作
     }

其中:

(1)[修饰符]是可选的,如public,后面章节将介绍具体内容。

(2)[其他限定]是可选的,如extends javax.swing.JFrame(见图2.12),以后介绍。

(3)类名:是该类的标识文字,在Java语言中属于标识符,由字母(区分大小写)、数字、下画线“_”和美元符号“$”等组合而成,且不能以数字开头,不能是单独一个下画线。习惯上,类名的第一个字母大写,其余字母小写,但由多个单词组成的类名则各单词的第一个字母大写。

(4)属性定义:是对该类所有对象共同具有的各种数据的定义,例如、文本字段类各个对象都需要确定和记录其中的文字是否可以编辑——editable属性、背景颜色——background属性、可以接受的字符个数——columns等;又如图2.13简单加法计算器类NumberAddition在窗口中创建的8个组件确定了该计算器显示的窗口内容,其中,169~176行语句就是定义这些属性。类中的属性又称为域变量,也叫字段,是在类中定义的一些变量。关于变量定义语句的细节将在第3章中介绍。

(5)方法定义:方法(有时也叫函数)是Java程序中完成特定任务的一个程序单元,执行了一些特定的操作。例如2.1节中设计的简单加法计算器类NumberAddition中,方法calcAdd完成用户所输入数据的加法运算,textClear方法完成清除三个文本框中内容的操作。关于方法定义格式等内容后续章节将进行介绍。

当给定了类名,确定了该类的属性,定义了它的方法后,就给出了这个类的定义。

在Java语言面向对象程序设计中,往往需要使用一些辅助工具帮助建模,最常用的是UML(统一建模语言)。类可以采用UML标示为如下形式:

例如,2.1节中设计的简单加法计算器项目中NumberAddition类可以绘制为如下UML类图。

必要时,第二个和第三个方框中的属性列表和方法列表可以不写出,而只给出类名。

2.3.3 类的组织

一个Java程序中可能会用到许多类,这些类有一些是开发者自己定义的,还有一些可能是标准类库中或其他组织开发的库中的类,还有可能是其他Java程序项目中的类。从表1.3可见,仅JDK 8所提供的Java标准类库中就有四千多个类和接口(一个接口可以看作一种特殊的类)。为了方便类的命名、开发、查找和管理,Java语言提供了包(package)分类组织各种类。Java语言采用了以句点分隔的层级结构为包命名,类似于Internet域名反顺序写法。例如,w2c组织的域名是w3c.org,那么它开发的一个Java包就取名为org.w3c.dom;又如,本书例题开发的GUI程序使用的是Java标准类库中的javax.swing包中的组件。Java的类一般都位于某个包中,定义方法是在该类的源程序文件最前面添加一条package语句。例如,1.4.4节中创建的Java程序(见图1.24)的第一条执行语句“package javaapplication1;”说明Hello类在名为javaapplication1的包中。如果在定义类时没有为其指定包名,则该类位于项目的默认包中。有了包组织的类的全名是“包名.类名”,例如,1.4.4节中的Java类Hello的全类名是javaapplication1.Hello,又如文本字段类的全类名是javax.swing.JTextField。

带有包名的类编译之后会创建与包名层次相同的目录结构,此时分隔包名各层次的句点就相当于目录分隔符。例如,1.4.4节中的Java类javaapplication1.Hello在命令提示符窗口中将当前目录转到源程序文件Hello.Java所在的目录下,执行编译命令“javac –d .Hello.java”,则在当前目录下自动创建子目录javaapplication1,并将编译生成的字节码文件Hello.class存放于其中。当然,NetBeans IDE编译时也会生成正确的相应目录结构。

在程序中要使用某个包中的类,可以采用带包名的全类名方式,如图2.12中的169~176行语句。此外,更方便的方法是在定义类的源文件中导入这些包中的类,然后不带包名而直接引用类名。类的导入语句是非常常用的Java语句,一般格式如下:

     import 包名.类名;

如果需要使用包中的多个类,则可以使用“*”代替类名,语句简化为:

     import 包名.*;

例如,可以在图2.12的NumberAddition.java文件的第6行添加语句“import javax.swing.*;”,然后将169~176行的语句修改为以下简化语句。

     private JButton jButtonCalc;
     private JButton jButtonClear;
     private JLabel jLabel1;
     private JLabel jLabel2;
     private JLabel jLabel3;
     private JTextField jTextFieldNum1;
     private JTextField jTextFieldNum2;
     private JTextField jTextFieldResult;

注意:NetBeans IDE自动生成的一些代码带有灰色背景显示,这些代码是不能修改的,称为保护代码块。例如,图2.12程序代码中的第168~177行语句就位于保护代码块中。

2.3.4 创建对象

定义了一个类就是给出了一个创建这种类型对象的模板,使用该类创建的对象都具有类所定义的属性和方法。类只是描述了它的对象中有什么,可以做什么,而程序运行时会创建每个对象并为其分配存储空间,此时对象才会存在。

Java语言使用new关键字创建对象。

例如,图2.12程序代码中第163行的“new NumberAddition()”被执行时会创建一个NumberAddition类的对象。单击图2.12“源”代码窗口26行前面的图标,如果27行前面还有图标再单击它,将会展开保护代码块,可以看到29~36行每一行都创建了一个对象。

29行的“new javax.swing.JLabel()”创建了一个javax.swing.JLabel类(标签组件)的对象,并返回该对象在内存中的引用——指向该对象在内存中存储块的链接,使用其前面的“=”将该引用“交给”(赋值)NumberAddition类对象的属性jLabel1(第171行定义)。30~36行同理。

一旦将对象的引用交给一个属性保存,该属性就通过引用与具体的对象联系起来,该属性也有了一个具体的值——属性值。更普遍的是使用变量(第3章介绍)保存对象的引用,属性也是一种变量。可以认为保存对象引用的变量名就是对象名,本书以后就这样叙述。之后就可以通过该属性(或变量)请求执行这个对象的操作,具体方法是在对象引用之后输入句点“.”,紧接着输入方法名及其他有关的内容。例如,图2.12“源”代码窗口163行的“new NumberAddition().setVisible(true);”语句是直接使用对象的引用请求执行其setVisible(true)方法,目的是显示程序窗口;第40行的“jLabel1.setText("第一个数:");”语句是使用保存第一个标签对象引用jLabel1的属性,请求设置该标签组件的显示文字为“第一个数:”。

使用“对象名.属性名”形式也可以直接使用该对象的指定属性。