本书从Java语言的基本特点入手, 全面介绍Java语言的基本概念和编程方法, 并深入介绍Java语言的高级特性。书中内容涉及Java语言中的基本语法、数据类型、类、异常、界面设计、小应用程序、I/O数据流、线程及网络功能等, 基本覆盖了Java语言的大部分实用技术, 是进一步使用Java语言进行技术开发的基础。《Java程序设计》内容详尽, 实例丰富, 在每章最后均列出了若干习题, 以方便教学。
辛运帏,女,博士,教授。现为南开大学计算机与控制工程学院计算机与信息安全系教授。多年来一直从事程序语言设计、数据结构与算法等方向的教学和科研工作,主讲数据结构与算法、形式语言与自动机、计算方法等课程。主要研究领域为人工智能、电子商务、加密技术、智能信息系统等,已出版《Java语言程序设计》、《数据结构》、《离散数学》等相关教材。
第5章 进一步讨论对象和类
5.1 抽象数据类型
5.1.1 概述
绝大多数程序设计语言都预定义了一些基本数据类型,并相应定义了对那些类型的实例执行的操作。比如,对整型、实型等数值类型,有加、减、乘、除等操作;对逻辑类型,有逻辑与、逻辑或、逻辑非等操作。
对于用户自定义的复合数据类型,需要由程序员自己定义一些方法,对该类型的实例进行所需的操作。在早期许多程序设计语言中,复合数据类型及其相关操作的代码之间没有特殊的联系。比如,用户定义日期Date类型,并定义一个方法tomorrow(),它接收一个Date类型的参数,据此推断其后继日是哪一天。程序中定义变量的代码和tomorrow()方法的代码可以是分离的。
有些编程语言改进了这种处理方式,允许数据类型说明和欲对该类型变量进行操作的代码说明之间有较紧密的联系。通常数据类型加上其上的操作称为抽象数据类型。严格地说,抽象数据类型是指基于一个逻辑类型的数据类型以及这个类型上的一组操作。每一个操作由它的输入、输出定义。一个抽象数据类型的定义并不涉及它的实现细节,这些实现细节对于抽象数据类型的用户是隐藏的。
程序5-1给出了Date类型和tomorrow操作间建立的一种联系。
程序5-1
public class Date {
private int day, month, year;
Date ( int i, int j, int k) {
?day = i;
?month = j;
?year = k;
}
Date() { //这是个构造方法,显式初始化
?day = 1;
?month = 1;
?year = 1998;
}
Date ( Date d) { //这是带一个参数的构造方法
?day = d.day;
?month = d.month;
?year = d.year;
}
public Date tomorrow() {
?Date d = new Date(this); //说明一个对象
?d.day++;
?if (d.day > d.daysInMonth()){//daysInMonth()返回每个月中不同的天数
d.day = 1;
d.month ++;
if (d.month > 12) {
d.month = 1;
d.year ++;
}
}
return d;
}
}
名为tomorrow的代码段在Java中叫作方法,也可以称为成员函数。
在有些程序设计语言中,tomorrow()方法的定义或许会要求带一个参数,例如:
void tomorrow(Date d);
像Java这种支持抽象数据类型的语言在数据和操作间建立了较严格的联系,即把方法与数据封装在一个类中。在程序中不是把方法描述为对数据的操作,而是认为数据知道如何修改自己,然后要求数据对它自己执行操作。相应的语句如下:
Data d = new Date ( 20, 11, 1998); //已初始化的date对象
d.tomorrow();
这种写法表明,数据自己执行操作,tomorrow()方法作用于变量d。要访问Date类的域,可使用点操作符“.”:
d.day
它的意思是“d所指的Date对象中的day域”。类似地,d.tomorrow()是指“调用d所指的Date对象中的tomorrow()方法”,即对d对象进行tomorrow操作。
把方法看作是数据的特性,而不把数据与方法分开,这种思想是建立面向对象系统过程中的重要步骤。
5.1.2 定义方法
定义一个抽象数据类型后,还需要为这个类型的对象定义相应的操作,也就是方法。在Java中,方法的定义方式类似于其他语言,尤其与C和C++ 很类似。定义的一般格式如下:
<修饰符> <返回类型> <名字>(<参数列表>)<块>
其中:
* <名字>是方法名,它必须使用合法的标识符。
* <返回类型>说明方法返回值的类型。如果方法不返回任何值,它应该声明为void。Java对待返回值的要求很严格,方法返回值必须与所说明的类型相匹配。如果方法说明有返回值,比如说是int,那么方法从任何一个分支返回时都必须返回一个整数值。
* <修饰符>段可以含几个不同的修饰符,其中限定访问权限的修饰符包括public、protected和private。public访问修饰符表示该方法可以被任何其他代码调用,而private表示方法只能被类中的其他方法调用。关于其他修饰符的说明请参考 2.5.3节。
* <参数列表>是传送给方法的参数表。表中各元素间以逗号分隔,每个元素由一个类型和一个标识符组成。
* <块>表示方法体,是要实际执行的代码段。
在例5-1中,为程序2-4中的Customer类定义了方法setName()和setAddress()。
例5-1 方法定义示例。
void setName (String name) {
this.name = name;
}
String getAddress() {
return address;
}
下面在Date类中增加daysInMonth()和printDate()方法,以便完善Date类。
程序5-2
public class Date {
private int day, month, year;
Date ( int i, int j, int k) {
day = i;
month = j;
year = k;
}
Date() { //构造方法
day = 1;
month = 1;
year = 1998;
}
Date ( Date d) { //带一个参数的构造方法
day = d.day;
month = d.month;
year = d.year;
}
public void printDate() {
System.out.print(day + "/" + month + "/" + year);
}
public Date tomorrow() {
Date d = new Date(this);
d.day++;
if (d.day > d.daysInMonth()) {
d.day = 1;
d.month ++;
if (d.month > 12) {
d.month = 1;
d.year ++;
}
}
return d;
}
public int daysInMonth() {
switch (month) {
case 1: case 3: case 5: case 7:
case 8: case 10: case 12:
return 31;
case 4: case 6: case 9: case 11:
return 30;
default:
if ( year % 100 != 0 && year % 4 == 0 ) {
return 29;
}
else return 28;
……