You are on page 1of 357

普通高等教育 “十一五” 国家级规划教材

Java 程序设计
Java programming
主 编 江 春 华
副主编吴劲蔡洪斌房春兰
Java
设计 Jovo Chengxu Sheji
.

人,创当时全球问类会议规模之纪录。1997 年 9 月,Java Developer Connection 社区成员超


过十万。1998 年 2 月,JDK1.1 被下载超过 2,000,000 次。
1998 年 12 月 4 日,JDK1.2 隆重发布,标志着 Java2 平台的诞生。
1998 年 12 月 8 日,Java2 企业级平台 J2EE 发布。
1999 年 6 月,SUN 公司发布 Java 的三个版本:标准版、企业版和微型版(J2SE、J2EE、
J2ME )。
今 J2SE ( Java 2 Standard Edition ):它是一组针对传统桌面应用的 API 和运行环境;
今 J2EE ( Java 2 Enterprise Edition ):它是 J2SE 的扩展集,主要用于在服务器端开发

可伸缩、可迁移、以数据库为核心的企业级应用;
今 J2ME ( Java 2 Micro Edition ): 它定义了一组针对嵌入式设备和消费电子设备的 API
.和运行环境 ,这些设备包括无线手持设备、PDA、电视机顶盒以及其他缺乏足够的资源去支
持 J2SE 的设备。
把 Java 2 平台分成三种版本使得它能够更好地满足不同目标领域中开发者的需求,同时
也使 Java 技术在保持其“编写一次,到处运行”精神的同时,在不同领域得到继续发展。
2000 年 5 月 8 日,JDK 1.3 发布。
2001 年 6 月 5 日,NOKIA 宣布,到 2003 年将出售 1 亿部支持 Java 的手机。
2001 年 9 月 24 日,J2EE1.3 发布。
2002 年 2 月 13 日,JDK 1.4 发布。
2002 年 2 月 2 6 日,J2SE1.4 发布,自此 Java 的计算能力有了大幅提升。
2004 年 9 月 30 日,J2SE1.5 发布,是 Java 语言的发展史上的又一里程碑事件。为了表
示这个版本的重要性,J2SE1.5 更名为 J2SE5.0。
2005 年 6 月,JavaOne 大会召开,SUN 公司公开 Java SE 6。此时,Java 的各种版本已
经更名以取消其中的数字“2” :J2EE 更名为 Java EE, J2SE 更名为 Java SE, J2ME 更名为
Java MEo
现在,在它诞生后的 10 年,Java 平台已经吸引了 400 多万软件开发商,全世界的每个
主要行业领域都在使用它,任何使用编程技术的设备、计算机和网络都在大范围地应用它。
事实上,Java 技术的多功能性 、有效性、平台的可移植性以及安全性已经使它成为网
络计算领域最完美的技术。因此到今天为止,Java 技术已经为 25 亿台设备提供支持:
今 7 亿 台 以 上 的 PC。
々 7 亿 8 百万部移动电话以及其他手持式设备。
今 10 亿个智能卡以及机顶盒、打印机、网络照相机、游戏、汽车导航系统、彩票终
端、医疗设备、收费站等。
今天,无论是互联网和科学超级计算机还是膝上型计算机和手机,无论是华尔街的市场
模拟器还是家庭游戏机和信用卡,在所有网络和设备上您都会看到 Java 技术的身影,它已
经无处不在。日臻完善、极度强大而且功能繁多的 Java 技术已经成了开发商的无价之宝,
利用它可以:
今在一个平台上编写软件,然后在另一个平台上运行。
々创建可在 Web 浏览器和 Web 服务中运行的程序。
今 开 发 适 用 于 联 机 论 坛、存储、投 票、HTML 格式处理以及其他用途的服务器端应
0鲁 Java 语言基础知识

简单数据类型的关键字, 存储空间开销、值大小及说明如表 2 3 所示。

-
表 2 3 Java 语言简单数据类型及存储空间开销
-
类型 存储(bit) 最小值/值 最大值/值 封装器类型 说明
boolean false Boolean 布尔型
char
byte 8
Unicode:0
128

Unicode:216 1
+127
- Character
Byte
字符型
字节整型
short 16 15
+2 Short 短整型
32 -231 +231 - 1 Integer 整型
long
float
64 +263 1
— Long 长整型
32 IEEE754 IEEE754 Float 单精度浮点型
double IEEE754 IEEE754 Double 双精度浮点型
void Void 无类型

Java 语言数据中的数值类型都是有符号(正负号)的,在贮存数值类型的数据时,其最高
位用来表示数据的正负号。
简单类型的变量被声明时,存储空间也同时被分配。该贮存空间只占用一个单一贮存单
元。对简单类型变量的访问则直接可以得到它的数据。
弓 I 用类型(如 String 或 class) 声明变量时,是不会为这个变量(即对象)分配存储空间的。
要使用 new 运算符来为引用类型的变量分配贮存空间。实际上,用类来声明的变量不是数
据本身 ,而是数据的引用(reference)。

弓I 用 类似 C/C++中的指针(pointer), 但是又不同于 C/C++中的指针,它的引用必须
由 Java 的虚拟机创建和管理。Java 语言本身不支持指针。
引用类型变量的值是一个数据的引用(即地址)。它是对占有由多个贮存单元构成的贮存
*

空间的引用。引用类型的变量通过点“ •”运算符访问它的成员。
简单数据类型还有对应的“封装器” (Wrapper)类。在对象实例中 ,为了把简单类型数
据像对象一样处理,则需要使用简单类型对应的封装器。有关封装器的概念将在后面相关章
节中讨论。
例如:
char a = ’A;

Character C = new Character(a);
也可以直接使用:
;
Character C = new Character('A')
在这个例子中,用封装器 Character 封装了 char 类型数据的’A’。

2.4 常 量

常量是指直接用于放入程序中的固定不变的值。它的表现形式有两种:数值和字符。

29
籲 鬱 Java 语言基础知识一 -
2.6 变量的作用域及初始化

2.6.1 作用域
变量的作用域是指能够程序执行中能够对变量访问的范围。变量一经声明,它在声明的
语句块中有效,所以变量的作用域就是变量所在声明的语句块,且不允许有相同标识符的变
量在同一个语句块中。依照作用域,变量可分为四类:
々成员变量

々异常处理的局部变量
成员变量是类中声明的变量。它的作用域在类中是全局的,可以被该类的方法访问。所
以在这个类中,也可以称它为全局变量。
方法的局部变量是方法或方法的参数所声明的变量。在方法中,该局部变量作用域是自
它声明处开始,到本段代码块结束为止可以访问。
语句的局部变量,是在语句块中声明创建的变量,它的作用域也是从声明开始,到这个
块结束。只有当程序执行到语句块时变量才可以访问。
异常处理的局部变量是在异常处理代码段中声明创建的变量。它的作用域也只能在相关
异常程序段被访问时有效,并随着这个程序段结束而失效。

ÿ
如图 2 2 所示,在这四类变量中,变量创建所处位置决定了变量的作用域。
在类 AppExa 中,声明了五个成员变量 idlnt,idChl ,idCh2,idFloat, idBool 和两个成员方
法 main()方法和 testProg()方法。五个成员变量 idlnt,idChl ,idCh2,idFloat,idBool 的作用域在
整个类的所有方法中可以访问。
在 main()方法中,有 idBool、x 及参数 arg 三个局部变量,它们的作用域是 main()方法
体,同时局部变量 idBool 与成员变量 idBool 同名,则在该方法中成员变量 idBool 被局变量
idBool 隐藏,如果要在 mainO中访问被隐藏的成员变量 idBool ,则需要在 idBool 前加 this,
即 this.idBool 表示成员变量 idBool, 有关这方面的进一步概念将在类中描述。
在 main()方法中的 while 循环的程序块中,创建的块局部变量 x 和 idlnt, 它的作用域是
在 while 循环程序块中,while 循环的局部变量 idlnt 隐藏了成员变量 idlnt, 它的局部变量 x
也隐藏了 main()方法的局部变量 x。随着 while 循环的结束,它的变量 x 和 idlnt 失效。
在 testProgO方法中, 声明了局部变量 idCh3,它的作用域是在该方法中, 只有当 testProog()
被调用时有效,并随着方法结束而失效。
在方法中定义的参数和变量被称为局部变量,也可以被称为自动(automatic )、临时
( temporary ) 或栈(stack ) 变量。
有关异常处理中的局部变量作用情况,将在异常处理的章节中讨论。

33
Java
设计 Java Chengxu Sheji

class AppExa{
int idlnt;
char idChl ,idCh2;
float idFloat;
boolean idBool ;
public static void main(String arg[]){
boolean idBool = true; 成员变童
局部变量
idBool idlnt

while (idBool) {
int x = 11 ;
4
作用域
idChl
块变量
成员变量 idCh2
int idlnt= l ;
idlnt 成员变量
idlnt
隐藏区 idBool idFloat
作用域
v 隐藏区
idBool

作用域
public void testProg(){
char idCh3; 局部变童
idCh3
v 用域

2.6.2 变量初始化
图22
- 变量的作用域示意图

变量初始化是指在声明一个变量时给变量赋值。 局部变量和成员变量在声明中可以初始
化。方法的参数变量和异常处理的参数变量是不能在声明时初始化,它们在被调用时通过实
际参数传递而赋值。
例 2.3 变量的初始化示例。
int idlnt = 100;
double pi = 3.14159265;
boolean idBool = false;
例子中,不仅创建了三个不同类型的变量,还对它们分别赋上了初始化的值。
变量初始化时所赋的值要符合变量的类型。它们的数据类型要一致或相容,否则是不能
赋值的。在某些数据类型之间,可以通过对值的类型作转换,使它和变量类型一致后再赋值
给变量。例 2.4 所展示的是非法与合法的赋值情况。
例 2.4 非法与合法对变量赋值。
int y = 3.1415926;

34
@0砂 Java 语言基础知识

//非法:3.1415926 不是整数,需转换为 int 后赋值。


int x =(int)3.1415926;
//合法:先将 3.1415926 转换为整数 3 后赋值给 x。
boolean truth = 1;
非法 • 一般错误,不像 C/C++中对布尔型赋 1 或 o 值。
"
float z = 3.14156;
//非法:3.14156 是双精度数,不能直接赋给 z,需转换。

-
float s (float)3,14156;
//合法:先将 3.14156 转换为 float, 再赋给 s。
例中合法与非法在注解中做了相应说明。有关类型转换概念将在后面小节中描述。
在 Java 程序中,任何变量都必须经初始化后才能被使用。在一般情况下,Java 虚拟机
自动初始化成员变量。在对象被创建时,Java 虚拟机对实例变量在分配存储空间时,自动赋
给实例变量相应的默认值。这其中对简单类型中的数值型实例变量均赋给 0 值。对字符型实
例变量赋给的'\u0000’值,这个值是 Unicode 中的第一字符。对布尔型实例变量赋给 false。
而对所有引用类型的实例变量赋给的是 null, 如 表 2 6 所 示。
-
类型
byte
-
表26 变置初始化的默认值

0
short

long OL
float O.Of
double O.Od
,
char ViOOOO
boolean false
引用类型 null

如果对 null 值的引用类型变量使用,会引起一个异常。所谓异常是指在运行时出现的错


误。所以不能使用 mill 值的引用类型变量。
类的实例变量在创建对象时会自动初始化。但是局部变量则必须显示地初始化,未被初
始化的局部变量被访问情况是会在编译器报错。
例 2.5 在下列编码段中,类的实例变量和局部变量初始化的情况。

InitialTest.java
*/
class InitialTest {
int varlnstance;
boolean blnst;
void setData(int intV,boolean boolV){
35
參0魯 Java 语言基础知识

opBl 和 opB2 是两个可以进行逻辑运算的操作数,它们可以实现的具体逻辑运算的使用方

-
式如表 2 13 所示。

表 2-13 布尔运算符

运算符 使用方法 功能 说 明
&& opBl && opB2 与 若 opB1,opB2 全 true 则为 ture,有 false 则 false
II opBl 1| opB2 或 若 opBl ,opB2 全 false 贝 j为 false, 有 true 贝ij ture
! opBl 非 若 opBl 是 true 贝U 为 false,是 false 贝U 为 true;

Java 的布尔运算符是一种优化的运算符。使用&& 和| 1 运算符的操作,并不一定对它


的两个操作数都要访问,由于这两个运算符的第一操作数在某种值的情况下,就可以确定结
果,就不用再去访问第二个操作数,这样简化了运算,也提高了程序的运行效率。&& 和| |
运算符的具体操作情况参照表 2 13 如下所示。
々运算符:
-
opBl 值为 false,则运算式的值就是 false,无论 opB2 的值是什么。所以
程序不会访问 opB2;
opBl 值为 true, 程序还需要 opB2 的值才能确定运算式的值,程序需要访
问 opB2 o
々| | 运算符:
opBl 值为 true, 则运算式的值就是 true, 无论 opB2 的值是什么。所以程
序不会访问 opB2;
opBl 值为 false, 程序还需要 opB2 的值才能确定运算式的值,程序需要
访问 opB2 a
在二进制位的布尔运算符&和1的逻辑运算等同 &&和 |
|。
通常,关系运算符和布尔运算符在一起使用,用于流控制语句的判断条件。对这种条件
运算式进行运算操作时,特别要注意操作数的优先级及类型。
例 2.7 关系运算符和布尔运算符用于流控制语句中的判断条件示例。
/**
源程序:RelatAndBoolOper.java
*/
public class RelatAndBoolOper {
public static void main(String args[]){
inta=25, b=3;
boolean d=a<b;
,,
System.out.println( a < b = " + d; )
int e=3;
if( e != 0 && a/e>5 ){
;
System.out.println("a / e = " + a/e)

41
Java
nil 设计 Java Chcngxu Sheji
值得注意的是,使用&和
| 运算符好处不大,由于它们的使用会降低程序的可读性,并且
可能导致错误。布尔型数据与数值类型数据不能互相转换。

2.7.5 赋值运算符和数据的类型转换
1 . 赋值运算符
赋值运算符“=”的作用是将数据写入到变量的贮存单元中。在“=”运算符的左边是
变量,右边则是待写入的数据值。

赋值操作必须注意:
*

今必须是将右边的数值赋给左边的变量;
今右边的数值类型要与左边的变量类型一致或相容;
,才能将右边的数值写入变量的贮存单元。

2. 数据类型转换
当二元运算符的操作数出现不同类型时,需要对操作数作相应的数据类型转换。
在 Java 语言中,由于不同类型的数值的取值范围不同,在数据类型转换时,必然会出
现“拓宽类型”和“缩窄类型”情况。
U
拓宽类型”是指把值范围小类型的数据转换成值范围大类型的数据。
缩窄类型”是指把值范围大类型的数据转换成值范围小类型的数据。
针对不同类型转换情况 ,Java 的数据类型转换分为自动类型转换和强制类型转换两种方
式:
今 自 动 类 型 转 换 是 指 Java 虚拟机自动地将数据类型实施转换。由于“拓宽类型”转
换,不造成数据访问的不安全,所以自动类型转换是“拓宽类型”的数据转换。如

-
表 2 17 所示是自动类型转换示例。

表 2-17 自动类型转换示例

运算式 说明
long intL
— 8;
int slnt = 98L;
8 是 int , intL 是 long, 拓宽类型可以。
98L 是 long,slnt 是 int,缩窄类型不可以。
double data = 8.56F; 8.56F 是 float,data 是 double, 拓宽类型可以。
float dataF = 9.09; 9.09 是 double,dataF 是 float,缩窄类型不可以。

今强制类型转换是指通过显式地将数据类型实施转换。
“缩窄类型”转换会造成数据 .

访问的不安全,所以必须通过强制转换实现数据的类型转换。强制类型转换形式如
T:
(type)identifier
其中:
表示数据类型名称。

44
流程控制、数组

System.out.println()
;
n=0;

}
}

运行程序:

java PrimeNumber

结果为:

Prime numbers between 100 and 200


101 103 107 109 113 127 131 137 139 149
151 157 163 167 173 179 181 191 193 197
199

3.4 return 语句
return 语句是用在方法中的。一个方法在调用结束后会返回,并带上这个方法指定类型
的数据(除非返回类型是 void)。 •
在返回类型为非 void 的方法中,程序流程执行 return 语句时使方法返回。方法返回所
带的数据由 return 语句所带的表达式给出。
当方法返回的数据类型是 void 时,return 语句是不能带表达式。它仅仅使方法返回,并
且方法不返回数据。

return 语句的格式为:
return [expression];
其中:
expression 为轰达式,它将作为方法调用返回时的返回值。
Java 语言中的一个方法返回的数据类型是非 void, 则在方法中必须有一个带表达式的
return 语句,这个表达式的数据类型必须和方法声明的返回类型一致。
如果方法声明的类型为 void,则方法中并不一定要有 return 语句,如果有 return 语句,
则 return 语句是不能带表达式的。
return 语句在方法中,逻辑上起到方法的最后一条语句功能。在 return 语句后面的语句
将不会被访问。通常会把不在最后位置上的 return 语句放在条件判断的程序块中。如例 3.9
和例 3.10 所示。

例 3.9 获取两个数中最大的数。

代码片段:方法 getMax(int,int)

61
Java
设计 Java Chengxu Sheji

*/
public int getMax(int a, int b){
return ( a > b ) ? a : b ;
}

方法 getMax(int, int)返回 int 类型的值,对应方法中的 return 语句所带的表达式( a > b ) ?


a:b 的值也是 int 类型,这个表达式的值作为方法的返回值。

例 3.10 为成员变量赋值。

代码片段:方法 setData(int, int)


*/
public void setData(int a, int b){
this.a = a ;
this.b = b ;
}
方法 setData( int, int )是 void 类型,说明该方法不需要返回值,所以在方法中可以没有
return 语句。如果有 return 语句,则 return 语句不能带表达式。

3.5 数组和字符串
正如前面讲述的数据类型,在 Java 中,数组是引用类型。数组类型是一种有序数据的
集合,数组中在每一维上的元素具有相同的数据类型。数组通过数组名和它的下标对数组元
素访问 ,数组元素的下标是不能越界的。数组元素数量是使用 new 运算符来确定的。
数组也是一个对象,数组声明不能创建对象本身,而创建的是一个引用,该引用可被用
来引用数组。数组元素使用的实际存储器可由 new 语句或数组初始化软件动态分配。
3.5.1 数组声明
Java 的数组声明采用与 C 语言类似的形式。数组可分为一维数组和多维数组。它们的声
明的形式为:

type arrayName[] [[] ” ] ;


或另一等价形式:

type[] [[]… ] arrayName;

其中:
Java 语言的任意数据类型;
arrayName 为数组名,它是一个合法的 Java 标识符;
/7在这里表示是数组的一维,而不是表示可选;

62
_
/Z7- . .7表示是数组的多维,是可选的。[]对的数量表示了数组维数的多少。
在声明数组时,“[]” 对既可以放在数组名的后面,也可以放在数组名的前面。
流程控制、数组

^
要注意的 ,“[]” 对中是空的,不能有数据, 这不同于 C/C++。数组的维数及元素的
数量是可以通过 new 运算符确定。
对于 Java 编程人员,可能更喜欢采用把 “[]” 放在数组名前面的声明形式。它更加清晰,
有利于程序的阅读。如下例所示:

例如:
int count[]; //一维整型数组 count
char ch[][]; //二维字符型数组 ch
float口 fNum; //一维浮点型数组 fNum
int口 testArray( int arraySize){
int[] aid;
aid = new int [arraySize;]
return aid;

在这个例子中,方法 testArray(int)返回数据类型是 int 类型的一维数组。其的局部变量


aid 也是 int 类型的一维数组,其元素的数量是参数 arraySize 的值给出。该方法返回的数组
就是 aid。
在 Java 语言中,数组的声明是不能确定数组大小,因为数组声明并没有给数组分配存
储单元。数组存储单元的分配可以由 new 运算符实现。在声明数组后,使用 new 运算符分
配存储单元的格式如下:
arrayName[][[]...] = new type [arraySize1][[]. ];


arrayName = new type [arraySizel ][[]..、];

其中:
是声明的数组名,它是一个引用类型的变量。
arraySizeI 是数组维上的元素个数 。在使用 new 运算符分配存储空间时,由 arraySize1
值给出分配在这一维上的元素数量。在 “ []”中 ,均可以填写一个数字来指明某维上的数
组元素个数。
ftps 是数组声明的类型。
运算符是在内存中分配存储单元的操作符。这种分配存储空间的操作也可以称之为
实例化。在 Java 语言中,引用类型变量的实例化都是可以通过 new 运算符实施的。
=运算符实现数组 arrayName 对 new 实例化的存储空间引用。 实质上就是将这个 new 实
例化的存储空间起始地址赋给了数组名 arrayName。
数组实质也是一种对象,具有对象的一些特性和处理方式。

例如:

首先声明数组:
63
Java
设计 Jovo Chengxu Shcji

int[][] score;

再分配存储空间并引用:

score = new int[3];


score[0] = new int[4]
socre[ l ] = new int[4]
score[2] = new int[4]

或另一种方式的分配存储空间并引用:

score = new int[3][4];


前部分的分配存储空间是 new 运算符首先对数组 score 的第一维分配了 3 个元素,然后
对 score 在第一维上的三个元素再分别作 new 的实例化处理,既第一维上每一个元素又是一
个有 4 个元素的数组。
例子后部分在 new 运算符处理中, 直接分配并确定了数组 score 在 2 个维上的元素数量。
对数组的声明和数组引用 new 的实例化,既可以分成两条语句实现,也可以合在一条
语句中实现,如下所示格式:

type arrayName[] [ []. .. ] = new type [arraySizel ][[] ] ;


•••


type[][[] ... ] arrayName = new type [arraySizel ][ [] ] ;
•"

例如:

int count[] = new int [10];


char[][] ch = new char [3][5];
float[] fNum = new float [20;
]
在这需要强调的是,数组使用 运算符实例化后,数组的元素都有了一个初始化的

-
值,如表 2 6 所示,无论数组是成员变量还是局部变量。所以该例中数值类型的数组 count
和 fNum 的元素初始化的值分别为 0 和 0.0F,而 char 类型数组元素初始化的值为’\u0000’。
3.5.2 数组元素及初始化
数组元素是数组通过下标对数组中的存储单元访问的变量。由 运算符实例化数组
后,可以通过“数组名”加“ []”的下标形式对元素进行访问。
#
在如乂& 语 中,在数组的每一维上,数组元素的下标是由“0”开始,到该维的“元素

-
。数组的下标是不能越界的,即:
的数量 1 ”

“元素的下标”<“元素的数量”

Java 对数组元素的下标进行越界检查,是为了以确保数据的安全。
通过下标访问数组元素,就如同使用变量一样。数组元素形式如下:

64

You might also like