·本章学习目标
熟悉Java编程的基础知识
掌握Java语言的基本数据类型、操作符、表达式
掌握Java程序的流程控制语句
熟悉并学会初步使用Java编程环境
·本章学习内容
数据类型
常量、变量与表达式
数据类型的转换
Ø 数组
Ø 流程控制语句
§2.1 数据类型
对于程序中的数据,编译程序会为其分配一块内存空间,内存空间的大小由该数据的数据类型来决定。
Java语言的数据类型分为两大类:基本类型(primitive type)和引用类型(reference type),相应也就有两种类型的变量。
2.1.1基本数据类型
基本类型是Java语言中预定义、长度固定、不能再分的类型,数据类型的名字也被当作关键字保留,且都小写。
在Java语言中,所有数据都必须严格定义其数据类型,且所有的变量都必须有初始值或默认值。Java语言的基本数据类型参见下页表。
基本数据类型
|
占内存
|
取值范围
|
默认值
|
数值型
|
整型
|
byte
|
1字节
|
- 128 ~ 127
|
(byte)0
|
short
|
2字节
|
- 32768 ~ 32767
|
(short)0
|
int
|
4字节
|
- 2147483648 ~ 2147483647 (即-215 ~ 215-1)
|
0
|
long
|
8字节
|
- 9223372036854775808L~ 9223372036854775807L (即-231 ~ 231-1)
|
0L
|
浮点型
|
float
|
4字节
|
对于负数:- 3.402823E38 ~ - 1.401298E-45
对于正数:1.401298E-45 ~ 3.402823E38
|
0.0F
|
double
|
8字节
|
对于负数:- 1.79769313486232E308 ~
- 4.94065645841247E-324
对于正数:4.94065645841247E-324~1.79769313486232E308
|
0.0
|
字符型
|
char
|
2字节
|
unicode字符,用单引号括起来
|
'"u0000'
|
布尔型
|
boolean
|
1字节
|
true,false
|
false
|
关于基本数据类型作几点说明:
由于字符皆用16个二进制位表示,所以Java语言设计了一个用8个二进制位来表示的byte数据类型,可用来表示AscII码。
Java语言中,布尔型(boolean)数据不再与整数相关,而是独立作为一种数据类型,并且不能与整数有任何自动转换关系。
Java语言中,char是唯一的无符号表示的数据类型。如果将char转换为int或者short,很可能得到一个负数。
浮点型的数据被0除时不会报错,而是输出“Infinity”,编程时一定要小心。
与很多其他编程语言中的字符串(String)和数组不同,Java语言将其作为对象处理,而不是作为基本数据类型。
与基本数据类型相对应的是引用数据类型即引用变量,包括对象、字符串、数组等。例如,Java语言通过类库中定义的String类与StringBuffer类处理字符串,所以字符串具有引用变量的特征。
引用类型的变量是由参数来控制的。当声明一个引用类型的变量之后,内存只分配一个空间用来存放此变量的地址,当调用它时只是将此对象存储地址传过去。只有当用new命令正式申请内存空间或直接初始化时,才会得到用来存放其值的空间。
2.1.2引用数据类型
引用类型的变量(即对象)的内存分配图:
2.1.3数值类型间的转换
Java在运算时总是要进行数据类型的检查,如果数据类型不一致,则按照某种规则进行转换,然后按照转换后的数据类型运算。如果这种转换不能进行,则会报告出错信息。
Java的自动数据类型转换只能完成由低级数据类型向高级数据类型的转换,也就是只能完成由占用内存少的数据类型向占用内存多的数据类型的转换。
设c = a + b,当a与b数据类型不同时自动数据类型转换如表2-3所示。
操作数a的数据类型
|
操作数b的数据类型
|
操作数b转换后的数据类型以及运算结果c的数据类型
|
int
|
byte或short
|
int
|
long
|
byte或short或int
|
long
|
float
|
byte或short或int或long
|
float
|
double
|
byte或short或int或long
|
double
|
int
|
char
|
int
|
如果需要由高级数据类型向低级数据类型的转换,就必须使用强制数据类型的转换,具体的方法是在需要转换的数据前面加上欲转换的数据类型,并用括号括起来。
【例】整型与浮点型的转换
float a = 1.414;
int b = (int) a;
其结果是b被赋值为1。
强制数据类型转换可能会导致数据精度的降低或导致数据溢出,要慎重使用。上例就是一个损失了数据精度的例子。
除了使用上述方法进行强制数据类型的转换之外,逻辑型数据与其他基本数据类型的转换需要一些技巧,下例是逻辑型与整型相互转换的例子。
【例】逻辑型与整型的转换
boolean b = false;
int i = 4;
b = ( i != 0 ); //把整型转换为逻辑型使b=true
i = ( b ) ? 1 : 0; //把逻辑型转换为整型使i=1
2.2 标识符和关键字
标识符可以理解为名字。在Java语言中,常量名、变量名、类名、对象名等都是标识符。标识符的命名遵守以下规则:
标识符由字母、数字、下划线或美元符$组成。
标识符的第一个字符必须是字母、下划线或美元符,从第二个字符开始也可以是数字。
不能以Java的关键字作为标识符。
Java语言对大小写是敏感的,即大写字符与小写字符被看作是不同的字符。
标识符可以任意长,在机器内部用Unicode字符集表示。
关键字就是保留字,关键字不能再被用做标识符。在Java语言中有近60个关键字,关键字分为如表所示的几类。
关键字类型
|
关键字
|
内构类型关键字
|
boolean true false char byte short int long float double void
|
表达式关键字
|
null this new super
|
语句关键字
|
选择语句
|
if else switch case break default
|
循环语句
|
for do while continue
|
控制转移语句
|
return throw
|
防卫语句
|
synchronized try catch finally
|
修饰符关键字
|
static abstract final private protected public transient volatile
|
用于类、方法及其相关目的的关键字
|
class instanceof throws native
|
用于扩展类构筑模块的关键字
|
extends interface implements package import
|
保留日后使用的关键字
|
cast const future generic goto inner operator outer rest var
|
2.3 常量和变量
2.3.1变量
变量是在程序运行过程中其值能够改变的量,通常用来保存计算结果或中间数据。在Java语言中变量必须先声明后使用,并且应当为变量赋初始值。
1. 变量的声明
type identifier1[, identifier2, …]
type为数据类型;identifier1[, identifier2, …]为一个或多个变量的标识符,即变量名。
【例】声明变量
int x, y; //定义 x, y两个整 型变量
float a, b, c; //定义a, b, c三个浮点型变量
2.为变量赋初值
定义变量之后要为变量赋初始值,具体做法是使用赋值语句。
【例】为以上定义的整型变量x、y和浮点变量a、b、c赋初值的语句。
x = 5;
y = x + 4;
a = 4.23F;
b = 2 * a;
c = a * a + b;
如果声明变量以后没有赋初值,则会产生一个“变量还未被初始化”的错误。
3.在声明变量时为变量赋初值
为变量赋初始值也可以在声明变量时进行,以下是把以上定义、赋初值两个步骤合并的做法。
【例】声明变量的同时赋初值
int x=5, y=x+4; //定义 x, y两个整型变量并赋初值
float a=4.23F, b=2*a, c=a*a+b; //定义a, b, c三个浮点型变量并赋初值
4.变量的有效范围与生存周期
变量的有效范围或生存周期就是声明该变量时所在的语句块,也就是用一对大括号{}括起的范围。一旦程序的执行离开了定义它的语句块,变量就变得没有意义,也就不再被使用了。
2.3.2常量
常量是在程序运行过程中其值始终不改变的量。常量分为直接常量和符号常量两种。直接常量就是不使用任何标识符直接引用其值的常量。
1.直接常量的后缀
使用数值型直接常量有时会引起多义性。例如直接常量“0”,就可能是byte或short或int或long或float或double类型的。为了避免这种情况的发生不加后缀时默认为int类型,此外Java为long、float和double类型的直接常量规定了使用后缀的方式,而对于byte和short类型的直接常量则只能使用强制数据类型转换,具体内容列于下页表中。
数制
|
表示方法
|
可表示的数据范围
|
十进制
|
默认的数制
|
|
八进制
|
以0开头的数字,数字由0到7组成
|
0000~0377相当于十进制的0~255
|
十六进制
|
以0x开头的数字,数字由0到F组成
|
0x0000~0xFFFF或0x00000000~0xFFFFFFFF
|
3.转义字符
为了更方便地在字符串中表示一些特殊字符,Java定义了转义字符“"”,紧接在转义字符右边的字符被解释成其他含义,或者说“"”及其右边的字符一起代表一个特殊的字符。这种方法给编程带来方便。表2-13给出了转义字符代表的意义。
转义字符
|
对应的unicode码
|
解释
|
'"b'
|
'"u0008'
|
退格
|
'"t'
|
'"u0009'
|
制表符
|
'"n'
|
'"u000A'
|
换行
|
'"f'
|
'"u000C'
|
表格符
|
'"r'
|
'"u000D'
|
回车
|
'""'(双引号)
|
'"u0022'
|
双引号
|
'"''(单引号)
|
'"u0027'
|
单引号
|
'""'
|
'"u005C'
|
反斜杠
|
'"000'(3位八进制数)
|
'"000'
|
能表示所有AscII字符
|
'"u0000'(4位十六进制数)
|
'"u0000'
|
能表示所有unicode字符
|
4.符号常量
符号常量的定义与变量类似,也是先定义一个标识符,然后通过标识符读取其值的常量。符号常量一经定义,其值不能被改变,这是与变量的根本区别。符号常量也象变量一样,每一个符号常量都有其数据类型和作用范围。按照一般的习惯,常量标识符中的英文字母使用大写字母。定义常量的方法是:
final type identifier1 = value1 [, identifier2 = value2, …]
其中修饰符final表示定义的是常量;type为数据类型;identifier1, identifier2, …为一个或多个常量的标识符,即常量名;value1,value2, …是常量的值。
【例】定义符号常量
final int x = 100, y = 200; //定义两个整型常量x, y
final float a = 0, b = 2.355; //定义两个浮点型常量a, b
2.4 运算符
2.4.1算术运算符
算术运算符是大家所熟识的。主要有两点需要说明:
求余运算符%的两个操作数,例如a%b中的a与b要求均为整型数据,其结果亦为整数。例如7%3=4,10%5=0。
对于加减乘除4个运算符,如果两个操作数属于同一种数据类型,其结果亦为此数据类型,如3*5=15,6/2=3。如果a与b的数据类型不同,则在Java中占用不同的字节数,如2*1.4=2.8,3.6/3=1.2等,其结果的数据类型与所占字节数多的数据类型相同。实际上Java在执行时,先将其中字节数少的操作数保存成与另一个操作数相同长度的形式,然后进行运算。
运算符就是进行某种运算的标识符号。
Java语言特别强调运算符执行顺序的概念。Java语言对运算符的优先级、结合性与求值顺序作了明确的规定。
算术运算符
|
说 明
|
+
|
正值运算符、加法运算符
|
-
|
负值运算符、减法运算符
|
*
|
乘法运算符
|
/
|
除法运算符
|
%
|
求余运算符
|
2.4.2自增、自减运算符
++、 --运算符的种类与用法如表所示。这类运算符常用于控制循环变量。
运算符
|
名称
|
说明
|
++i
|
前自增
|
i参与相关运算之前先加1后参与相关运算
|
i++
|
后自增
|
i先参与其相关运算,然后再使i值加1
|
--i
|
前自减
|
i参与相关运算之前先减1后参与相关运算
|
i--
|
后自减
|
i先参与其相关运算,然后再使i值减1
|
一般说来,++i与i++都是使i=i+1,而--i与i--都是使i=i-1,但注意自增、自减运算符放在变量前还是放在变量后的不同。
前自增(减)时,先使变量加1或减1后,再去参与其它运算;后自增(减)时,先让变量参与运算,然后再对当时的变量值加1或减1。
【例】int x = 2; int y = (++x)*3; 则x,y的值分别为3,9
先使x加1,然后执行乘法运算,最后赋值给y。
【例】int x = 2; int y = (x++)*3; 则x,y的值分别为3,6
先让x值参与乘法运算,然后x自加1,最后将乘法运算结果赋给y。
自增、自减运算符只能用于变量,而不能用于常量和表达式,如8++与(a+c)++是没有意义也是不合法的。
自增、自减运算符的结合性为自右至左,而且只作用于它所操作的变量,丝毫不影响该变量参与其它运算。
【例】设i原值为4,则执行 k=(i++)+(i++)+(i++); 后,i和k的值分别多少?
k值为12,i值为7,这是因为i++为变量后自增,所以i先参与其相它运算,即k=i+i+i=12。然后,i再执行变量后自增运算,按执行顺序自左至右,共自增3次,故i值为7。
同样道理,设i值为4,执行 g=(++i)+(++i)+(++i); 后,i和k的值分别多少?
i值为7,g值为21,即先对变量i进行三次增值后,再执行连加运算,得到g值。
2.4.3关系运算符
关系运算进行比较运算,通过两个值的比较,得到一个boolean(逻辑)型的比较的结果,其值为“true”或“false”。在Java语言中“true”或“false”不能用“0”或“1”来表示,而且这两个逻辑值必须用小写“true”与“false”。
优先级
|
运算符
|
名称
|
用途举例
|
高
|
instanceof
|
实例为
|
if ( v instanceof convertible)
|
<
|
小于
|
a<b,3<2
|
>
|
大于
|
a>b,45>44
|
<=
|
小于等于
|
a<=b,23<=23
|
>=
|
大于等于
|
a>=b,23>=23
|
低
|
==
|
等于
|
x==y,x==5
|
!=
|
不等于
|
x!=y,x!=5
|
关系运算符常常用于逻辑判断,如用在if结构控制分支和循环结构控制循环等处。7个关系运算符中,等于“==”和不等于“!=”同属一个优先级,另外5个运算符同属一个优先级,且前者的优先级别低于后者。在同一优先级中遵循自左至右的执行顺序。关系运算符常常与下一节中的逻辑运算符混合用。
注意:“==”运算符和”=”运算符是完全不同的,前者是关系运算符,而后者是赋值运算符。
2.4.4逻辑运算符
Java语言中,提供了6种逻辑运算符,逻辑运算符的运算结果为逻辑型“true”或“false”。下表介绍了各种逻辑运算符。
优先级
|
运算符
|
名称
|
用法举例
|
说明
|
高
|
!
|
逻辑非
|
!a
|
a为真时得假,a为假时得真
|
低
|
&
|
逻辑与
|
a & b
|
a和b都为真时才得真
|
&&
|
简洁逻辑与
|
a && b
|
a和b都为真时才得真
|
|
|
逻辑或
|
a | b
|
a和b都为假时才得假
|
||
|
简洁逻辑或
|
a || b
|
a和b都为假时才得假
|
^
|
逻辑异或
|
a ^ b
|
a和b的逻辑值不相同时的真
|
逻辑运算表达式的执行顺序为自左至右,逻辑非运算符“!”的优先级高于其它逻辑运算符。
Java语言中的位运算符如下表所示。
优先级
|
运算符
|
名称
|
用法举例
|
说明
|
见表
2-8
|
&
|
按位与
|
a & b
|
两个操作数对应位分别进行与运算
|
|
|
按位或
|
a | b
|
两个操作数对应位分别进行或运算
|
^
|
按位异或
|
a ^ b
|
两个操作数对应位分别进行异或运算
|
~
|
按位取反
|
~ a
|
操作数各位分别进行非运算
|
<<
|
按位左移
|
a << b
|
把第一个操作数左移第二个操作数指定的位,溢出的高位丢弃,低位补0
|
>>
|
带符号按位右移
|
a >> b
|
把第一个操作数右移第二个操作数指定的位,溢出的低位丢弃,高位用原来高位的值补充
|
>>>
|
不带符号按位右移
|
a >>> b
|
把第一个操作数右移第二个操作数指定的位,溢出的低位丢弃,高位补0
|
2.4.5位运算符
【例】计算表达式的值
设short a = 0x2F34; short b = 0xE5081
(1)求a & b
(2)求a | b
(3)求a ^ b
(4)求a << 3
(5)求b >> 3
(6)求b >>> 3
计算时先把a和b化成16位的二进制的数,
a = 00101111 00110100,b = 11100101 00001000
然后进行按位运算后,再换算成16进制的数。
(1)换算成16进制,结果为0x2500。
(2)换算成16进制,结果为0xEF3C。
(3)换算成16进制,结果为0xCA3C。
(4)左移n位相当于原数乘以2的n次幂,并且左移比乘法快,所以有时用左移代替乘2的n次幂的运算。换算成16进制,结果为0x79A0。
(5)换算成16进制,结果为0xFCA1。
(6)换算成16进制,结果为0x1CA1。
如果两个不同长度的数值做位运算,系统将二者的右端(即低位)对齐,同时将两个操作数中长度较短者的高位用0补齐。
2.4.6条件运算符
条件运算符的使用方式由“?”和“:”连接的三个操作数构成,一般的形式为:
表达式1?表达式2:表达式3
上式执行的顺序为:先求解表达式1,若为真,取表达式2的值作为最终结果返回,若为假,取表达式3的值为最终结果返回。
条件运算符的优先级仅高于赋值运算符。结合性为自左向右。
【例】设a = 5,b = 8,c = 1,d = 9,求下式的值。
( a > b ) ? a : ( c > d ) ? c : d
由于结合性为自右向左,故先计算( c > d ) ? c : d。因为1 > 9为false,故取d(= 9)为返回结果。此时,再求( a > b ) ? a : d,即最终结果为9。
2.4.7赋值运算符
赋值运算符把常量、变量或表达式的值赋给一个变量,赋值运算符用等号“=”表示。为了简化、精练程序、提高编译效率,可以在“=”之前加上其它运算符组成扩展赋值运算符。
使用扩展赋值运算符的一般形式为:
<变量><扩展赋值运算符><表达式>
其的作用相当于:<变量>=<变量><运算符><表达式>
其中,<赋值运算符>为“<运算符>=”。
下页表给出了各种扩展赋值运算符的用法。
扩展赋值运算符
|
用法举例
|
等效的表达式
|
+=
|
a += b
|
a= a + b
|
-=
|
a -= b
|
a = a - b
|
*=
|
a *= b
|
a = a * b
|
/=
|
a /= b
|
a = a / b
|
%=
|
a %= b
|
a = a % b
|
&=
|
a &= b
|
a = a & b
|
|=
|
a |= b
|
a = a | b
|
^=
|
a ^= b
|
a = a ^ b
|
<<=
|
a <<= n
|
a = a << n
|
>>=
|
a >>= n
|
a = a >> n
|
>>>=
|
a >>>= n
|
a = a >>> n
|
赋值运算符遵循从右至左的结合性,看如下的例子。
【例】已知整形变量a,b,c,计算以下各式的值。
a = b = c = 5;
a = 5 + ( c = 6 ) - ( d = 2 );
a + = a * = b - = ( a = 4 ) * ( b = 2 );
计算过程如下:
第一式相当于a = ( b = ( c = 5 ) )其结果使得a、b、c皆为5。
第二式的结果为d=2,c=6,a=9。
而第三式的计算过程是:
第1步:a = 4,b = 2
第2步:b = 2 - 4 * 2 = -6
第3步:a = a * b = 4 * -6 = -24
第4步;a = a + a = -24 - 24 = -48
2.4.8运算符的优先级和结合性
在Java语言中,每个运算符分属于各个优先级,同时,每个运算符具有特定的结合性。有的具有左结合性,即自左至右的结合原则;有的具有右结合性,即自右至左的结合原则。运算符在表达式中的执行顺序为:首先遵循优先级原则,优先级高的运算符先执行。在优先级同级的运算符之间遵守结合性原则,或自左至右,或自右至左。
下页表给出了各种运算符的功能说明、优先级和结合性,绝大部分在以上各小节已经分别介绍过。需要补充说明的是,“+”除了作为正号运算符与加法运算符之外,还可以起到字符串的链接作用。
优先级
|
运算符
|
结合性
|
说明
|
1
|
, . ; ( ) [ ] {}
|
|
分隔符
|
2
|
++ -- !
|
右→左
|
自增、自减、非
|
3
|
* / %
|
左→右
|
乘、除、求余
|
4
|
+ -
|
左→右
|
加、减
|
5
|
<< >> >>>
|
左→右
|
左移、右移、右移补0
|
6
|
Instanceof < <= > >=
|
左→右
|
实例为、小于、小于等于、大于、大于等于
|
7
|
== !=
|
左→右
|
等于、不等于
|
8
|
&
|
左→右
|
位与
|
9
|
^
|
左→右
|
位异或
|
10
|
|
|
左→右
|
位或
|
11
|
&&
|
左→右
|
与
|
12
|
||
|
左→右
|
或
|
13
|
?:
|
左→右
|
条件运算
|
14
|
= *= /= %= += -= <<= >>= >>>= &= ^= |=
|
右→左
|
赋值
|
由于严格规定了优先级和结合性,Java语言能高效灵活地运用这些赋值运算符,同时也会使初学者困惑不解。以下再举两个例子说明。
【例】已知整形变量i,计算下式及变量i的值
( i = 4 ) * i++
计算过程:执行时变量i首先被赋值为4,后做乘法得16,这是整个表达式的值,同时由于i++使变量i自身的值为5。
从上表中可以看出,逻辑非优于算术运算符和关系运算符,而逻辑或和逻辑与低于关系运算符,所以,在进行逻辑表达式的求值时,应该注意区分操作数是作为算术运算对象、关系运算对象还是逻辑运算对象。
【例】求下面表达式的值
7 > 6 || 4 < 5 && 3.6 > 0.2
计算过程:
按照自左至右的执行顺序,因为关系运算优先于逻辑运算,先得出7 > 6为true,则无论逻辑或下一个操作数为true还是false,逻辑表达式7 > 6 || 4 < 5值为真,此时得到true && 3.6 > 0.2,对于逻辑与而言,第一个操作数为真,还须判断第二个操作数的值才能得出结果,而3.6 > 0.2得true,表达式化为true && true,最后得出此表达式最终结果为true。
2.5 表达式
表达式是由运算符、操作数以及方法调用组成的,用来说明运算过程并返回运算结果。表达式可以嵌套,表达式的计算根据运算符的优先级和结合性进行,当数据类型不一致时会自动进行数据类型的转换,如果转换不能进行,就会产生错误。
【例】分析以下程序的运算结果
int x = 2000000000, y = 20, z;
z = x * y / 100;
System.out.println("z="+z);
计算过程:如果按照一般数学运算的方法,结果应当是2000000000 * 20 / 100 = 400000000,但在计算机上运行的结果为13452943。其原因是当计算x * y时,因两个操作数都是int型,结果也应当是int型,但40000000000超出int型的范围,得到的是1345294336,除以100并化成int就是13452943。
若把程序中的第3行改为: z = x * ( y / 100);
也不能得到正确的结果,只能得到0。其原因是当计算y / 100时得0.2,结果应当是int型的,化成int就是0,所以最后输出一个错误的结果0。
对于本例,只要把数据类型定义为long就能得到正确的结果,程序如下:
long x, y, z;
x = 2000000000;
y = 20;
z = x * y / 100;
System.out.println( "z=" + z );
由此看来,在设计程序时宁愿把数据类型设计得宽裕些,也不要计划得过于紧张,以免这类“莫名其妙”的错误发生。
2.6 数组
2.6.1一维数组、
·一维数组的声明
数组声明的格式为:
类型 数组名[ ]; 或者 类型[ ] 数组名;
注:数组名为Java标识符。“[ ]”部分指明该变量是一个数组类型变量。
【例】int arr1[];
char[] arr2;
说明:声明了名为arr1的整型数组和名为arr2的字符型数组。
·一维数组的创建
要用new操作来构造数组,即在数组声明之后为数组元素分配存储空间,同时对数组元素进行初始化。其构造格式如下:
数组名=new 类型[数组长度];
例如,list=new int[3];
注:它为整型数据组list分配3个整数元素的内存空间,并使每个元素初值为0。
为简化起见,还可以把数组的说明和构造合在一起,其格式如下:
类型数组名[ ]= new 类型[数组长度];
·数组的初始化
数组初始化就是为数组元素指定初始值。通常在构造数组时,Jave会使每个数组元素初始化为一个默认值。但在许多情况下,并不希望数组的初值为默认值,此时,就需要用赋值语句来对数组进行初始化。
【例】给一个长度为5的整形数组的元素依次赋值0,1,2,3,4,并倒序打印输出该数组的元素值。
public class ArrTest{
public static void main(string args[]){
int i;
int a[] = new int[5];
for(i = 0; i < 5; i++)
a[i] = i;
for(i = a.length -1; i>=0; i--)
System.out.println(“a[“+i+”]=“+a[i]);
}
}
·数组元素的使用
数组元素的标识方式为:
数组名[下标]
其中下标为非负的整型常数或表达式,其数据类型只能为byte,short,int, 而不能为long。
若在Java程序中超出了对数组下标的使用范围(例如,数组的最大下标为5,但是在程序中存取了下标为8或-4的元素),则在运行此程序时将出现如下错误信息:
Exception in thread″main″
java.lang.ArrayIndexOutOfBoundsException
2.6.2多维数组
·二维数组的说明与创建
二维数组说明的格式为:类型数组名[ ] [ ];
例如: int intArray[ ] [ ];
对二维数组来说,分配内存空间有下面几种方法:
(1)直接为每一维分配空间,如:
int a[ ] [ ] = new int[2] [3];
该语句创建了一个二维数组a,其较高一维含两个元素,下图为该数组的示意图。
A[0][0]
|
a[0][1]
|
a[0][2]
|
A[1][0]
|
a[1][1]
|
a[1][2]
|
从最高维开始,分别为每一维分配空间,如:
int b[ ][ ] = new int[2] [ ]; //最高维含2个元素,每个元素为一个整型数组
b[0] = new int[3]; //最高维第一个元素是一个长度为3的整型数组
b[1] = new int[5]; //最高维第二个元素是一个长度为5的整型数组
该数组的示意图为:
b[0][0]
|
b[0][1]
|
B[0][2]
|
|
b[1][0]
|
b[1][1]
|
B[1][2]
|
b[1][3]
|
b[1][4]
|
注意:使用运算符new来分配内存时,多维数组至少要给出最高维的大小。
如果在程序中出现 int a2[ ] [ ] =new int[ ] [ ];
编译器将要提示如下错误:
Array dimension missing
·二维数组元素的初始化
二维数组元素的初始化有两种方式:
(1)直接对每个元素进行赋值;
(2)在说明数组的同时进行初始化。
·二数组元素的引用
对二维数组中每个元素,其引用方式为:
数组名[下标1] [下标2];
其中下标1、下标2为非负的整型常数或表达式,如:a[2] [3] 、cc[i+2][j*3 ](i,j为整数)等。同样,每一维的下标取值都从0开始。
Java语言中的程序流程控制结构包括分支结构、循环结构、控制转移结构和防护结构四类,其中防护结构是Java语言所特有的,将在以后章节中介绍。本节先介绍前三类结构。
2.7 程序流程控制结构
2.7.1分支结构
Java的选择结构包括if结构和switch结构两种。
1.If结构
if结构的基本形式是:
if (条件表达式) 语句1;
[ else 语句2; ]
其中,“else 语句体”可选。在if语句中条件表达式的值必须是一个逻辑型。如果表达式的值是非逻辑型,系统将会报错。语句可以是一条语句,或用“{}”括起来的多条语句的语句体。
2. 嵌套的if结构
嵌套if结构的形式是:
if (条件表达式1) 语句1;
else if (条件表达式2) 语句2;
……
[ else 语句3; ]
如果不省略“else 语句3;”,这种嵌套的if结构总是只能满足一个条件因而只能执行一条语句;
如果省略“else 语句3;”,这种嵌套的if结构可能满足一个条件因而执行一条语句,也可能所有条件都不满足因而一条语句也不执行。同基本形式的if结构一样,各语句可以是一条语句,或是用“{}”括起来的语句体。
3.switch选择结构
switch选择结构的基本形式为:
switch (表达式){
case值1: {语句体1};[ break;]
case值2: {语句体2};[ break;]
……
case值n: {语句体n}; [break;]
[ defaultl: {语句体n+1}; [break;] ]
}
switch选择语句的表达式的值应为一个byte、short、int、char类型的数值。
switch选择结构的常用目的就是为了从众多情况中选择所希望的一种去执行,故而,每一分支语句中都用break语句作为结束。如果忽略掉break语句,程序将继续测试并有可能执行下一分支,直到遇到break语句或当前switch语句体结束,这往往不是程序员所希望的。
switch选择语句中可以有一个default语句作为其它情况都不匹配时的出口。
Java语言中有3种形式的循环结构,分别是for结构、while结构以及do…while结构。在Java语言中可以随时说明局部变量加以利用,并且仅在说明的程序块中有效。循环结构中常用此类局部变量作为循环变量,当循环结束时,局部变量亦被内存空间释放掉,这种动态的分配内存的机制很方便,不易出错且节约内存。
2.7.2循环结构
1.for循环结构
for循环结构的一般格式为:
for (循环初始值; 循环条件; 循环增长量){ 循环体 }
for循环结构中的初始值、测试条件及增长量皆由表达式组成,三者皆为可选的,既可以在for循环结构之前设定好循环初始值,也可以在for循环结构体内对增长量加以设定。如果连测试条件都没有,那么将是无穷循环,如:
for( ; ; ){}
“循环初始值; 循环条件; 循环增长量”三者之间用分号“;”隔开,故每个部分可以有几个表达式,每个表达式之间用逗号“,”隔开。如:
for(i = 0,j = 0; i + j < 100; i++, j += 2)
for结构常常临时说明局部变量作为循环变量使用,当for循环结束时,这种临时局部变量即失效。如:
for (int i=0; i<10; i ++) {}
2.while循环结构
while循环结构的表达形式为:
while (循环条件){ 语句体 }
其中“循环条件”为一个逻辑表达式。
while循环结构在每一次循环之前先计算逻辑表达式的值,如果为真,执行语句体;如果为假,转而执行语句体的下一条语句。也就是说,语句体可能循环执行多次也可能一次也不被执行。
3.do…while循环结构
do…while循环结构的表达形式为:
do{
语句体
}while (表达式);
其中“循环条件”为一个逻辑表达式。与while循环结构不同的是,do…while循环结构的语句体至少被执行一次。也就是说,do…while循环结构先执行一次语句体,再计算逻辑表达式的值,如果为真,再去执行语句体;为假,执行下一段程序。
在分支结构和循环结构中有时需要提前继续或提前退出分支结构和循环结构,为实现这一功能,要配合使用continue语句和break语句。下面介绍这两个语句。
4.continue语句
continue语句有两种形式:
continue;
continue 标号;
continue语句的作用就是提前继续下一个循环,即:如果正在进行第N次循环,就增加循环变量,测试循环条件,如果符合,进入第N+1次循环。
第二种用法“continue标号;”用在希望结束内部循环而继续外部循环,同时不希望外部循环从头开始。就事先在外部循环处加上标号,并在循环体中用“continue标号;”语句实现这种跳转。所谓标号由一个标识符加冒号组成。
【例】“continue 标号”的使用
计算年月。变量m表示月份,变量d表示日期。当m = 2且d = 28时,执行“continue months”语句,跳出内部循环,转到标号months处,并开始执行m = 3的循环。程序如下:
months: for(int m=1; m<=12;m++){
for(int d=1; d<=31; d++){
if(m==2&&d==28)
continue months ;
……
}
}
5.break语句
break语句亦有两种形式:
break;
break标号;
break语句用于for、while、do…while与switch结构中,其作用与continue语句正好相反。执行break语句时,程序跳转到循环结构或选择结构语句块的结束处,执行下一条语句。
使用第二种用法“break标号;”时,应在程序中事先定义一个匹配的标号,且此标号必须在一个完整程序块开始处。这一程序块可以为任何语句,不一定是循环语句或switch语句,这与“continue标号;”中的标号位置不同,在continue中标号必须在外部循环开始处。
【例】“break 标号”的使用。
months: for ( int m = 1; m <= 12, m++ ){
for (int d = 1; d <= 31; d++ ){
if ( cost > budget )
break months;
……
}
}
2.7.3控制转移语句
控制转移语句有以下两种表达形式:
return;
return (表达式);
控制转移语句用于从方法中返回上一级程序。使用第二种形式能向上一级程序返回值一个返回值。若方法的返回值设定为“void”类型,则只能使用第一种返回形式。
最后,处理异常情况的“throw”语句也属于控制转移语句,将在第8章进行详细介绍。
2.7.4其他语句
除了前面介绍的程序结构语句之外Java还使用其他几种语句,其中有的在前面的例子中已经使用过了,现介绍如下。
1.方法调用语句
方法调用语句用于调用指定对象的指定方法,一般用法是:
对象名.方法名(参数表)
例如:System.out.println ( "Good!" )
就调用System.out 对象的println方法显示一个字符串“Good!”。
2.表达式语句
表达式也是Java语句,例如以下语句都是表达式语句:
a = b + c;
c = (a++) + (++b) + a * 2 + b * b
3.空语句
空语句就是只有一个分号的语句,空语句什么也不做,只用在有意识形成空循环时。例如以下语句空循环100次。
for ( int i = 1 , i <= 100, i++ );
4.复合语句
复合语句就是由{}括起来的由若干语句组成的语句块。
2.8 注释
注释是程序员为增强程序可读性常用的一种辅助手段,良好注释的习惯将有助于对程序的理解和程序设计清晰度的提高,便于程序的日后维护。
Java语言有3种注释方式:
以“//”开始的注释。即可用于一行的行尾,也可单独占用一行。
以“/*”开始到下一个“*/”结束的注释,这种注释往往占用多行。
以“/**”开始,到“*/”结束的注释。这种注释是为自动产生程序文档设计的。
Java语言中注释不能嵌套。例如在“/*”与“*/”之间出现了“*/”,就会产生错误。
·小结
本章介绍的内容是Java语言的重要组成部分。学习本章以后应当能正确地使用关键字和标识符,能按照语法要求正确地书写程序。
掌握各种运算符的功能、使用方法和优先级,能使用常量、变量、运算符正确地组成表达式。
掌握使用if和switch选择语句形成程序分支的方法。
掌握使用for,while,do结构形成循环程序的方法。
理解控制转移语句return的两种用法。
结合习题学习掌握典型问题的编程方法。