1、标识符
Java语言的字符使用Unicode编码标准。Unicode字符集中的每个字符为16位编码。这样,Java语言的字符就不仅可以表示常用的ASCII字符,即数字0~9、英文字母A~Z、a~z以及+、-、*、/等常用符号,还可以表示如汉字、拉丁语、希腊语等其他语言文字。
标识符是由字母、数字、下划线(_)、美元符($)组成的、必须以字母、下划线或美元符开头的、字符个数有限的字符序列。如i、count、myStack、GetValue、_length等都是合法的标识符。Java语言在定义标识符时,其字母符号区分大小写(或称是大小写敏感的),所以count、Count、COUNT表示不同的标识符。标识符可以用来命名变量名、常量名、类名等。
Java语言中有固定含义的标识符称作关键字。用户不允许用关键字定义标识符。Java语言中的关键字共有47个,如下表所示。
abstract boolean break byte case catch
char class continue default do double
else extends false final finally float
for if implements import instanceof int
interface long native new null package
private protected public return short static
super switch synchronized this throw throws
transient true try void while
注:goto也是保留的关键字,虽然不能在java中使用
2、变量和常量
程序通常要处理数据,处理数据首先要保存数据。程序中要保存的数据都需要系统分配内存空间。变量和常量都需要系统分配内存空间。
变量:
变量是一个保存数据的内存区域的名字。变量在使用时必须先定义(或称声明),然后才能用赋值语句(或其他形式)来为其赋值。
变量定义是指示编译器为特定数据类型的数值保存在内存中分配适当的内存空间。这样,在随后的程序中就可以用赋值语句(或其他形式,如在变量定义时直接给出初始值)为该变量赋值。变量名的命名必须符合2.1节所说的标识符的命名规定。
变量声明的格式为:
<数据类型名><变量名表>;
随着程序规模的扩大,经常是多人合作完成一个程序的编写。为了防止变量使用的混乱,变量的使用范围是受限的,每个变量只在自己的使用范围内有效。变量的使用范围称作变量的作用域。变量的使用范围是定义该变量的程序块。
【例2.1】关于变量作用域的示例
public class Example2_1
{
public static void main(String args[])
{
int i = 10, j;
j = 20;
{
int k = 100;
System.out.println("k = " + k );
}
// System.out.println("i = " + i + " j = " + j + " k = " + k);
System.out.println("i = " + i + " j = " + j );
}
}
程序运行结果:
k = 100
i = 10 j = 20
程序说明:
在main函数中,定义了int类型的变量i和j,变量i在定义时给了初始化值10,变量j随后用赋值语句赋了数值20。在此程序块中,输出语句输出了变量i和j的当前数值。在下一层程序块(即下一层的花括号所括的范围)内,又定义了int类型的变量k,由于此变量k的作用范围只限于下一层程序块内,所以输出语句中如果包括了变量k(即如果使用了注释掉的语句),则编译器将指示错误。
在程序设计中,例子中所示的程序块形式并不多见。常见的程序块形式是if语句、while语句、for语句等后面跟随的一对花括号。以此类推,可以知道,在一个函数中定义的变量只在该函数内有效。
常量:
在程序设计中,有时需要定义一个变量,并要求该变量在整个程序运行期间保持不变,这种在整个程序运行期间保持不变的变量称作常量。常量也是一种标识符,所以定义常量时也要符合标识符的规定。
定义常量的方法是在定义变量的语句最前面加上关键字final。
和变量类同,常量定义也是指示编译器为特定数据类型的数值保存在内存中分配适当的内存空间。常量和变量惟一的不同之处是,常量只允许在定义时给出其数值,并不允许在随后的程序中改变其数值。在习惯上,常量名通常为全大写字母。例如:final int MAXSIZE = 100; 就定义了常量MAXSIZE等于100。
3、基本数据类型
数据类型规定了一类数据的数据位长度(或称字符个数)、取值范围以及对该类数据所能进行的操作。
Java语言中共定义了8种基本数据类型,其中4种为整型数,2种为浮点型数,1种为字符型数,1种为布尔型数。数据类型不同,所定义的变量占用的内存空间、取值范围以及对该类数据所能进行的操作也不同。
Java语言定义的8种基本数据类型及相应的关键字如下:
整 型:byte 、short、 int、 long
浮点型:float、double
逻辑型:boolean
字符型:char
1.整型
整型数是零和有限范围的正整数和负整数。由于4种不同整型数的数据位不同,所以相应的正整数和负整数的范围也不同。
Java的整数类型
类型 数据位 数值范围
字节型byte 8 bits -128——127(即-2^7——2^7-1)
短整型short 16 bits -32768——32767(即-2^15——2^15-1)
整 型int 32 bits -2147483648——2147483647(即-2^31——2^31-1)
长整型long 64 bits -9223372036854775808——9223372036854775807(即-2^63——2^63-1)
Java的整型数可以表示为十进制、八进制或十六进制。具体表示方法为:
十进制:用若干个0~9之间的数字表示,并规定首位不能为0,如123。
八进制:以0打头,后跟若干个0~7之间的数字,如0123。
十六进制:以0x或0X打头,后跟若干个0~9之间的数字以及a~f之间的小写字母或A~F之间的大写字母,a~f或A~F分别表示数值10~15,如0X123E。
注:字面值是在程序中用到的显式数据值,如123就是一个字面值。
Java语言规定,所有的整型字面值都隐含为int型。
若要将一个整数字面值明确地表示为long型时,需在后面加L或l,如21474836470L或12345l。
2.浮点型
浮点型数由整数部分和小数部分组成。浮点型数用来表示实数。浮点数有两种表示方式:
标准记数法:由整数部分、小数点和小数部分构成。如123.123,123.0。
科学记数法:由整数、小数点、小数和指数部分构成,指数部分由一个e或E后跟带正负号的整数表示。如123.123用科学记数法可表示为1.23123E+2。需要注意的是,科学记数法中,一个浮点型数的整数部分不一定是小数点前的整数。
浮点型数可以表示精度很高的或带有小数部分的数值。当一个变量要保存此类数值时,该变量必须定义为浮点型变量。
Java语言的浮点型有float和double两种。浮点数类型的类型、数据位和数值范围如下:
Java的浮点数类型
类型 数据位 数值范围
单精度浮点float 32 bits 3.4e-038——3.4e+038
双精度浮点double 64 bits 1.7e-308——1.7e+308
Java语言规定,所有的浮点型字面值都隐含为double型。若要将一个浮点型字面值明确地表示为float型时,需在后面加F或f,如123.123F或1.23123E+2f。
在定义变量时,对于整型变量或浮点型变量,要认真分析变量可能的取值范围,并选择合适的数据类型来定义变量,以免造成内存空间浪费,或由于超出数值范围或数值精度不够而造成出错。例如,如果一个变量的取值为确定的1到1000,则该变量应定义成short类型。又例如,如果一个变量的可能取值无法准确估计,则应按该变量可能的最大数值、并保留相当的宽裕程度来选择该变量的数据类型。
3.逻辑型
逻辑型用来定义保存逻辑值的变量。逻辑型也称为布尔型。逻辑值只有真(true)和假(false)两个值。
所有逻辑运算(如a<b)的运算结果值都是逻辑值,如当a = 4,b = 6时,逻辑运算a<b的结果值就是true。
逻辑型数值主要用在流程控制语句中的条件表达式,如if、while、for等语句的条件表达式都是逻辑型数值。
4.字符型
Java语言中,一个Unicode标准下的编码称作一个字符。Unicode标准用16位编码表示一个字符。字符型用来表示字符型变量和字符型字面值。
Java语言中,字符型字面值用一对单引号括起来,如'a'、'A'、'#'等都是字符型字面值。由于一些控制字符不能在屏幕上直接显示,以及字符串中特殊符号的表示等问题,需要有特殊方法表示这些符号。不能直接显示的控制字符字面值、或字符串中特殊符号表示使用转义字符的表示方法。
转义字符类型
转义字符 含义
/n 换行,将光标移至下一行的开始
/t 水平制表,将光标移至下个制表符位置
/r 回车,将光标移至当前行的开始
// 反斜杠,输出一个反斜杠
/’ 单引号,输出一个单引号
/” 双引号,输出一个双引号
如系统标准输出语句System.out.print()表示输出字符串后不换行,下面的输出语句:
System.out.print("Hello!/n");表示输出字符串"Hello!"后换行。
4、赋值语句
赋值语句的语法形式是:
<变量> = <表达式>;
赋值语句中,等号(称作赋值号)是赋值语句的标识,<表达式>可以是一个常量,或另一个已赋过值的变量,或是由运算符组成的一个表达式。是把一个常量或另一个已赋过值的变量中的数值赋给另一个变量。当一个变量被用赋值语句重新赋值时,该变量原先的赋值就被冲掉了,即该变量原先的赋值就没有了。
Java语言是一种强类型语言,所谓强类型语言是指数据类型的匹配要求十分严格。如果一个表达式的数据类型不一致等问题出现,则编译器给出类型不一致的出错信息。关于赋值语句的类型匹配有以下两种情况:
(1)类型相同。类型相同是指赋值号左端的数据类型和赋值号右端的数据类型完全一致。此种情况可以正确赋值。例如:
int smallValue =100; //类型相同
long bigValue = 100L; //类型相同
(2)类型兼容。类型兼容是指赋值号左端的数据类型比赋值号右端的数据类型长。此时系统会自动将赋值号右端的数据类型转化成和赋值号左端一样的数据类型。这里所说的数据类型长,是指数据类型的位数长,如long类型就比int类型的位数长。例如:
long bigval = 100; //100是int类型,将自动转化为100L
double x = 12.345F; //12.345F是float类型,将自动转化为12.345
(3)类型不兼容。若赋值号右端的数据类型比赋值号左端的数据类型长则类型不兼容。此时系统在编译时会产生“可能存在精度损失”的编译错误。例如:
int smallValuel = 100L; // 100L 是long类型,不兼容
float x = 12.345; //12.345是double类型,不兼容
当出现类型不兼容错误时,有两种解决方法:
重新定义赋值号左端变量的数据类型,使之变成满足要求的较长的数据类型。
用强制类型转换方法把赋值号右端的数据类型转换成和赋值号左端相同的数据类型。但要注意,强制类型转换可能丢失数据或损失数据的精度。
强制类型转换的格式为:
(<目标类型>)<表达式>
例如:
int i;
long k = 100L;
i = (int) k; //把变量k中的数值强制转换成int类型后赋给变量i
5、运算符和表达式
在Java语言之前,C语言和C++语言是最为广泛使用的高级程序设计语言,为了使Java语言能尽快被程序设计人员接受,Java语言设计者采用了把基本关键字和基本语句设计成和C/C++语言相同形式的方法。因此,对于已经掌握C/C++语言的人来说,Java语言在基本关键字、运算符、表达式、赋值语句、流程控制语句等方面,是和C/C++语言基本相同的。
Java的运算符可分为4类:算术运算符、关系运算符、逻辑运算符和位运算符。
1.算术运算符
Java的算术运算符分为一元运算符和二元运算符。一元运算符只有一个操作数;二元运算符有两个操作数,运算符位于两个操作数之间。算术运算符的操作数必须是数值类型。
(1)一元运算符:
一元运算符有:正(+)、负(-)、加1(++)和减1(--)4个。
加1、减1运算符只允许用于数值类型的变量,不允许用于表达式中。加1、减1运算符既可放在变量之前(如++i),也可放在变量之后(如i++),两者的差别是:如果放在变量之前(如++i),则变量值先加1或减1,然后进行其他相应的操作(主要是赋值操作);如果放在变量之后(如i++),则先进行其他相应的操作,然后再进行变量值加1或减1。
例如:
int i=6,j,k,m,n;
j = +i; //取原值,即j=6
k = -i; //取负值,即k=-6
m = i++; //先m=i,再i=i+1,即m=6,i=7
m = ++i; //先i=i+1,再m=i,即i=7,m=7
n = j--; //先n=j,再j=j-1,即n=6,j=5
n = --j; //先j=j-1,再n=j,即j=5,n=5
在书写时还要注意的是:一元运算符与其前后的操作数之间不允许有空格,否则编译时会出错。
(2)二元运算符
二元运算符有:加(+)、减(-)、乘(*)、除(/)、取余(%)。其中+、-、*、/完成加、减、乘、除四则运算,%是求两个操作数相除后的余数。
%求余操作举例:
a % b = a - (a / b) * b
取余运算符既可用于两个操作数都是整数的情况,也可用于两个操作数都是浮点数(或一个操作数是浮点数)的情况。当两个操作数都是浮点数时,例如7.6 % 2.9时,计算结果为:7.6 - 2 * 2.9 = 1.8。
当两个操作数都是int类型数时,a%b的计算公式为:
a % b = a - (int)(a / b) * b
当两个操作数都是long类型(或其他整数类型)数时,a%b的计算公式可以类推。
当参加二元运算的两个操作数的数据类型不同时,所得结果的数据类型与精度较高(或位数更长)的那种数据类型一致。
例如:
7 / 3 //整除,运算结果为2
7.0 / 3 //除法,运算结果为2.33333,即结果与精度较高的类型一致
7 % 3 //取余,运算结果为1
7.0 % 3 //取余,运算结果为1.0
-7 % 3 //取余,运算结果为-1,即运算结果的符号与左操作数相同
7 % -3 //取余,运算结果为1,即运算结果的符号与左操作数相同
2.关系运算符
关系运算符用于比较两个数值之间的大小,其运算结果为一个逻辑类型的数值。关系运算符有六个:等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=)。
例如:
9 <= 8 //运算结果为false
9.9 >= 8.8 //运算结果为true
'A' < 'a' //运算结果为true,因字符'A'的Unicode编码值小于字符'a'的
要说明的是,对于大于等于(或小于等于)关系运算符来说,只有大于和等于两种关系运算都不成立时其结果值才为false,只要有一种(大于或等于)关系运算成立其结果值即为true。例如,对于9 <= 8,9既不小于8也不等于8,所以9 <= 8 的运算结果为false。对于9 >= 9,因9等于9,所以9 >= 9的运算结果为true。
3.逻辑运算符
逻辑运算符要求操作数的数据类型为逻辑型,其运算结果也是逻辑型值。逻辑运算符有:逻辑与(&&)、逻辑或(||)、逻辑非(!)、逻辑异或(^)、逻辑与(&)、逻辑或(|)。
真值表是表示逻辑运算功能的一种直观方法,其具体方法是把逻辑运算的所有可能值用表格形式全部罗列出来。Java语言逻辑运算符的真值表如下:
逻辑运算符的真值表
A B A&&B A||B !A A^B A&B A|B
false false false false true false false false
true false false true false true false true
false true false true true true false true
true true true true false false true true
前两列是参与逻辑运算的两个逻辑变量,共有4种可能,所以表2.5共有4行。后6列分别是6个逻辑运算符在逻辑变量A和逻辑变量B取不同数值时的运算结果值。
要说明的是,两种逻辑与(&&和&)的运算规则基本相同,两种逻辑或(||和|)的运算规则也基本相同。其区别是:&和|运算是把逻辑表达式全部计算完,而&&和||运算具有短路计算功能。所谓短路计算,是指系统从左至右进行逻辑表达式的计算,一旦出现计算结果已经确定的情况,则计算过程即被终止。对于&&运算来说,只要运算符左端的值为false,则因无论运算符右端的值为true或为false,其最终结果都为false。所以,系统一旦判断出&&运算符左端的值为false,则系统将终止其后的计算过程;对于 || 运算来说,只要运算符左端的值为true,则因无论运算符右端的值为true或为false,其最终结果都为true。所以,系统一旦判断出|| 运算符左端的值为true,则系统将终止其后的计算过程。
例如,有如下逻辑表达式:
(i>=1) && (i<=100)
此时,若i等于0,则系统判断出i>=1的计算结果为false后,系统马上得出该逻辑表达式的最终计算结果为false,因此,系统不继续判断i<=100的值。短路计算功能可以提高程序的运行速度。
作者建议读者:在程序设计时使用&&和||运算符,不使用&和|运算符。
用逻辑与(&&)、逻辑或(||)和逻辑非(!)可以组合出各种可能的逻辑表达式。逻辑表达式主要用在 if、while等语句的条件组合上。
例如:
int i = 1;
while(i>=1) && (i<=100) i++; //循环过程
上述程序段的循环过程将i++语句循环执行100次。
4.位运算符
位运算是以二进制位为单位进行的运算,其操作数和运算结果都是整型值。
位运算符共有7个,分别是:位与(&)、位或(|)、位非(~)、位异或(^)、右移(>>)、左移(<<)、0填充的右移(>>>)。
位运算的位与(&)、位或(|)、位非(~)、位异或(^)与逻辑运算的相应操作的真值表完全相同,其差别只是位运算操作的操作数和运算结果都是二进制整数,而逻辑运算相应操作的操作数和运算结果都是逻辑值。
位运算示例
运算符 名称 示例 说明
& 位与 x&y 把x和y按位求与
| 位或 x|y 把x和y按位求或
~ 位非 ~x 把x按位求非
^ 位异或 x^y 把x和y按位求异或
>> 右移 x>>y 把x的各位右移y位
<< 左移 x<<y 把x的各位左移y位
>>> 右移 x>>>y 把x的各位右移y位,左边填0
举例说明:
(1)有如下程序段:
int x = 64; //x等于二进制数的01000000
int y = 70; //y等于二进制数的01000110
int z = x&y //z等于二进制数的01000000
即运算结果为z等于二进制数01000000。位或、位非、位异或的运算方法类同。
(2)右移是将一个二进制数按指定移动的位数向右移位,移掉的被丢弃,左边移进的部分或者补0(当该数为正时),或者补1(当该数为负时)。这是因为整数在机器内部采用补码表示法,正数的符号位为0,负数的符号位为1。例如,对于如下程序段:
int x = 70; //x等于二进制数的01000110
int y = 2;
int z = x>>y //z等于二进制数的00010001
即运算结果为z等于二进制数00010001,即z等于十进制数17。
对于如下程序段:
int x = -70; //x等于二进制数的11000110
int y = 2;
int z = x>>y //z等于二进制数的11101110
即运算结果为z等于二进制数11101110,即z等于十进制数-18。要透彻理解右移和左移操作,读者需要掌握整数机器数的补码表示法。
(3)0填充的右移(>>>)是不论被移动数是正数还是负数,左边移进的部分一律补0。
5.其他运算符
(1)赋值运算符与其他运算符的简捷使用方式
赋值运算符可以与二元算术运算符、逻辑运算符和位运算符组合成简捷运算符,从而可以简化一些常用表达式的书写。
赋值运算符与其他运算符的简捷使用方式
运算符 用法 等价于 说明
+= s+=i s=s+i s,i是数值型
-= s-=i s=s-i s,i是数值型
*= s*=i s=s*i s,i是数值型
/= s/=i s=s/i s,i是数值型
%= s%=i s=s%i s,i是数值型
&= a&=b a=a&b a,b是逻辑型或整型
|= a|=b a=a|b a,b是逻辑型或整型
^= A^=b a=a^b a,b是逻辑型或整型
<<= s<<=i s=s<<i s,i是整型
>>= s>>=i s=s>>i s,i是整型
>>>= s>>>=i s=s>>>i s,i是整型
(2)方括号[]和圆括号()运算符
方括号[]是数组运算符,方括号[]中的数值是数组的下标,整个表达式就代表数组中该下标所在位置的元素值。
圆括号()运算符用于改变表达式中运算符的优先级。
(3)字符串加(+)运算符
当操作数是字符串时,加(+)运算符用来合并两个字符串;当加(+)运算符的一边是字符串,另一边是数值时,机器将自动将数值转换为字符串,这种情况在输出语句中很常见。如对于如下程序段:
int max = 100;
System.out.println("max = "+max);
计算机屏幕的输出结果为:max = 100,即此时是把变量max中的整数值100转换成字符串100输出的。
(4)条件运算符(?:)
条件运算符(?:)的语法形式为:
<表达式1> ?<表达式2> : <表达式3>
条件运算符的运算方法是:先计算<表达式1>的值,当<表达式1>的值为true时,则将<表达式2>的值作为整个表达式的值;当<表达式1>的值为false时,则将<表达式3>的值作为整个表达式的值。如:
int a=1,b=2,max;
max = a>b?a:b; //max等于2
(5)强制类型转换符
强制类型转换符能将一个表达式的类型强制转换为某一指定数据类型,其语法形式为:
(<类型>)<表达式>
(6)对象运算符instanceof
对象运算符instanceof用来测试一个指定对象是否是指定类(或它的子类)的实例,若是则返回true,否则返回false。
(7)点运算符
点运算符“.”的功能有两个:一是引用类中成员,二是指示包的层次等级。
6.运算符的优先级
以下按优先级从高到低的次序列出Java语言中的所有运算符,表中结合性一列中的“左右”表示其运算次序为从左向右,“右左”表示其运算次序为从右向左。
优先级 运算符 结合性
1 . [] () ; ,
2 ++ ―― += ! ~ +(一元) -(一元) 右左
3 * / % 左右
4 +(二元) -(二元) 左右
5 << >> >>> 左右
6 < > <= >= instanceof 左右
7 = = != 左右
8 & 左右
9 ^ 左右
10 | 左右
11 && 左右
12 || 左右
13 ?: 右左
14 = *= /= %= += -= <<= >>= >>>= &= ^= |= 右左
7.表达式
用运算符和圆括号把运算对象连接起来的、符合Java语言语法规则的式子称作表达式。运算符是算术运算符的表达式称作算术表达式,运算符是关系运算符的表达式称作关系表达式,运算符是逻辑运算符的表达式称作逻辑表达式,运算符是位运算符的表达式称作位表达式。算术表达式中的运算对象必须是数值量,关系表达式中的运算对象必须是数值量,逻辑表达式中的运算对象必须是逻辑量,位表达式中的运算对象必须是整数数值量。
运算符都有优先级,表达式按照运算符的优先级进行逐个计算,最后求得整个表达式的值。运算符中圆括号的优先级最高,圆括号还可以多层嵌套。在同一级括号内(或一个括号也没有时),表达式按照运算符优先级高的先运算、同一运算符优先级的按照运算符的结合性(即从左向右还是从右向左)的次序进行运算。大多数运算符的结合性是从左向右,少数运算符的结合性(如赋值、条件运算等)是从右向左。
由于运算对象是有数据类型的,所以最终得到的计算结果也是有数据类型的,表达式结果的数据类型不一定和运算对象相同,它还取决于表达式的运算符。如:
int i=5;
(i<0)&(i>100) //结果为boolean型
(i-2)*8+5 //结果为int型
"Abcde"+"12345" //结果为String型
Java表达式既可以单独组成语句,也可出现在循环语句、条件语句的条件部分,还可以出现在函数的实际参数调用等场合。
实际上,从表达式的角度看,整个赋值语句是一个表达式,其运算方法是先计算出赋值运算符右边的表达式的值(因赋值运算符的优先级最低),然后把该值赋给赋值运算符左边的变量(因赋值运算符的结合性是先右后左)。
最后,我们给出一个例子,用来说明上面讨论过的Java语言基本要素。
【例2.2】求4x2 + 5x + 1 = 0方程的根。已知b2 – 4ac > 0。
public class Exam2_2
{
public static void main(String args[])
{
double a = 4, b = 5, c = 1, disc, x1, x2, p, q;
disc = b * b - 4 * a * c;
p = - b / (2 * a);
q = Math.sqrt(disc) / (2 * a);
x1 = p + q;
x2 = p - q;
System.out.println("x1 = " + x1 + " x2 = " + x2);
}
}
其中,表达式Math.sqrt()为调用Math类的sqrt()方法,该表达式完成某个数的开平方。此例还说明,表达式还可以是某个类的方法调用(当然,数据类型要符合要求)。
程序运行结果为:
x1 = -0.25 x2 = -1.0
6、流程控制语句
流程控制语句用来控制程序的执行流程。流程控制语句有条件选择语句、循环语句和转移语句三种。
任何程序的结构都是由三种基本的结构组成的。这三种基本结构是:顺序结构、分支结构和循环结构。在Java程序中,通常一个以分号(;)结束的符号串称为一条语句。在顺序结构的程序或程序段中,程序是按语句次序、下一条语句接上一条语句顺序被执行的。
在分支结构或循环结构的程序或程序段中,程序不是按语句次序顺序执行的,而是按分支结构语句或循环结构语句所规定的执行流程来执行的。为了满足实际应用问题的设计需要,分支结构和循环结构有各种各样的变形。另外,实际的程序设计中,经常需要转移语句与分支语句或循环语句结合使用。
Java语言的流程控制语句有:
分支语句:if,switch
循环语句:for ,while,do-while
转移语句:break,continue
另外,函数或类的成员函数在运行结束后,需要返回原调用处,并可能需要带回函数或成员函数的返回值,这种流程控制用return语句来实现。
1、分支语句
分支结构是指程序按照当前的分支条件控制程序流程的执行。
有:if语句和switch语句
if语句实现二路分支,switch语句实现多路分支。
1.if语句
(1)基本的if 语句
if 语句的语法形式为:
if (<逻辑表达式>)
<语句组1>;
[else <语句组2>;]
其中,逻辑表达式的计算值是一个只可能是true或false的逻辑值。if语句的含义是:当<逻辑表达式>的值为true时,执行if 后面的<语句组1>;当<逻辑表达式>的值为false时,执行else后面的<语句组2>。当执行的语句组中的语句多于一条时,语句组必须用一对花括号“{}”括起来。在Java语言的语法中,一对方括号“[]”括起来的部分,表示该部分(除数组定义外)是任选的。因此,else语句是任选的,当没有else语句时,若<逻辑表达式>的值为false时就执行if 语句后边的语句。
【例2.3】找出a、b两个数中的较大者并输出。
方法一:用if-else结构实现。
public class Exam2_3
{
public static void main(String args[])
{
int a = 5, b = 6, max;
if( a > b )
{
max = a;
System.out.println("max = " + max);
}
else
{
max = b;
System.out.println("max = " + max);
}
}
}
方法二:用没有else的if结构实现。
public class Exam2_3_2
{
public static void main(String args[])
{
int a = 5, b = 6, max;
max = a;
if( b > a )
max = b;
System.out.println("max = " + max);
}
}
例2.3中if语句的逻辑表达式中只有一个条件。当问题复杂时,if语句的逻辑表达式中的条件可能多于一个,这称为复合条件。
复合条件需要用逻辑运算符——逻辑与(&&)、逻辑或(||)、逻辑非(!)、逻辑异或(^)等逻辑运算符来组合条件。
例如下面的if语句条件为,判断n是否为一个1至100区间的数:
if (n >= 1 && n <= 100)
如果n既大于等于1又小于等于100,则条件为true,否则条件为false。
(2)if语句嵌套
如果if语句中又包括另一个if语句,则称为if语句嵌套。
if (n >= 1)
{
if (n <= 100) ……
}
else ……
在两个嵌套的if语句中,如果有一个if语句省略了else语句,会产生二义性。如:
if (n >= 1)
if (n <= 100) ……
else ……
此时,else是和哪个if语句匹配容易产生混淆。Java语言规定:else总是与最近的一个if语句匹配。
所以此处else应理解为是与第二个if语句匹配(注意:书写的缩进格式与匹配无关)。如果要求else是与第一个if语句匹配,则程序应写为:
一个if语句可以有两个分支,利用if语句嵌套可以组合出多于两个的分支。
【例2.4】找出三个整数中的最大数并输出。
方法一:用if语句嵌套方法。
public class Exam2_4
{
public static void main(String args[])
{
int a = 3, b = 1, c = 2, max;
if(a < b)
if (b < c)
max = c;
else
max = b;
else
if (a < c)
max = c;
else
max = a;
System.out.println("max = " + max);
}
}
程序运行结果:
max = 3
方法二:用条件的逻辑组合方法。
public class Exam2_4_2
{
public static void main(String args[])
{
int a = 3, b = 1, c = 2, max;
if(a < b && b < c)
max = c;
else if(a < b && c < b)
max = b;
else if (a > b && a < c)
max = c;
else //即(a > b && a > c)
max = a;
System.out.println("max = " + max);
}
}
说明:条件两两组合,所以条件的逻辑组合共有四种情况。此问题可不考虑两个数相等的情况。
2.switch语句
switch语句是多个分支的流程控制语句
语法形式为:
switch (<表达式>)
{
case<常量1>:<语句组1>;
[break;]
case<常量2>:<语句组2>;
[break;]
……;
[default;<语句组>]
}
其中switch、case 、default是关键字,default语句是任选的。
switch语句的语义是:将<表达式>的值按照从上至下的顺序与case语句中给出的常量值进行比较,当表达式的值与某个case语句中的常量值相等时,就执行相应case后的语句序列;若没有一个常量值与表达式的值相等,则执行default语句。如果没有default语句,并且表达式与所有case的常量都不相等时,则不做任何操作。
switch表达式和case常量值的类型可以是byte、short、int、long和char,但不能为boolean,并且要求两者的数据类型必须一致。
3.switch语句中的break语句
switch语句本身并不能保证执行完一组case后的语句或语句组后,跳过随后的case判断,通常情况下,此时需要用break语句来跳过随后的case语句。
break语句的语法形式是:
break;
switch语句中的break语句的语义是:跳过break语句所在位置随后所有的case语句,即结束switch语句的执行。
【例2.5】 把数值表示的星期转换成相应的英文表示并显示。
public class Exam2_5
{
public static void main(String args[])
{
int week = 5;
System.out.print("week = " + week + " ");
switch (week)
{
case 0: System.out.println("Sunday"); break;
case 1: System.out.println("Monday"); break;
case 2: System.out.println("Tuesday"); break;
case 3: System.out.println("Wednesday");break;
case 4: System.out.println("Thursday"); break;
case 5: System.out.println("Friday"); break;
case 6: System.out.println("Saturday"); break;
default: System.out.println("Data Error!");
}
}
}
程序运行结果:
week = 5 Friday
2、循环语句
循环结构是指程序按照当前的循环条件控制程序流程的执行。Java语言有三种循环结构的语句:for语句、while语句和do-while语句。这三种循环语句虽然控制循环的方式不同,但实现循环的功能相同。换句话说,对于任何一个循环问题,这三种循环语句都可以实现。但是,不同的循环问题,使用这三种循环语句的简便程度不同。因此,一个好的程序设计者,应该学会针对不同的循环问题,选择最简便的循环语句。
1.for语句
for语句的语法形式为:
for ([<表达式1>];[<表达式2>];[<表达式3>])
<循环体>;
for语句的语义是:首先计算<表达式1>的值,然后计算<表达式2>的值,如果<表达式2>值为true时,执行一次<循环体>,再计算<表达式3>的值,并进行下一次循环过程;当<表达式2>的值为false时,循环过程结束。
在for语句中,<表达式1>是给循环变量赋初值,因此,<表达式1>通常是一个赋值表达式;<表达式2>是给出循环结束条件,因此,<表达式2>必须是一个关系表达式或逻辑表达式;<表达式3>是改变循环变量,因此,<表达式3>必须是一个赋值表达式(或类似i++形式的改变变量i的数值的语句);<循环体>可以是一条语句,也可以是多条语句,当为多条语句时,必须用一对花括号“{}”括起来。
说明:无论是<表达式1>还是<表达式2>或者是<表达式3>,都可以任选。
【例2.6】 求1到10的累加和。
for语句最适合于循环次数已知的循环结构。此问题的循环次数已知,因此,此问题适合于用for语句实现。
public class Exam2_6
{
public static void main(String args[])
{
int i, n = 10, sum = 0;
for(i = 1; i <= n; i++)
sum = sum + i;
System.out.println("Sum = " + sum);
}
}
程序运行结果为:
Sum = 55
上述for语句循环过程也可以设计成递减形式的,此时的for语句为:
for(i = n; i >= 1; i--)
sum = sum + i;
2.while语句
while语句的语法形式为:
while (<逻辑表达式>)
<循环体>;
while语句的语义是:如果<逻辑表达式>的计算结果为true时,则执行循环体;如果<逻辑表达式>的计算结果为false时,则结束while语句的执行。同样,当<循环体>中的语句多于一条时,需要用一对花括号“{}”括起来。
例如用while语句实现求1到10累加和的程序段如下:
int i = 1,n = 10,sum = 0;
while (i <= n)
{
sum = sum + i;
i++;
}
和for语句相比,while语句循环中的循环变量赋初值(i = 1)、循环过程结束判断(i <= n)和循环变量修改(i++)三个部分都有,只是放在了不同的地方。
在while语句的循环结构中,初学者最容易犯的一个错误是,忘记在循环体中修改循环变量的值,此时循环过程将永不结束,俗称为“死循环”。如上面的程序段中如果没有i++语句,则循环过程将永不结束。
死循环的另一种情况是,循环结束条件永远无法满足。例如:
int i = 1,n = 10,sum = 0;
while (i >= 0)
{
sum = sum + i;
i++;
}
上述程序段的循环体中虽然有i++语句改变循环变量i的值,但i值的变化永远都满足i >= 0,即循环结束条件永远不会满足,因此造成死循环。
while语句适合于循环次数不确定的情况。如上所示,虽然while语句也可以用来构造循环次数已知的循环过程,但是,很显然,此种情况用for语句构造循环过程更简单、更明了一些。
【例2.7】求两个不为0的正整数的最大公约数。
对于求两个不为0的正整数的最大公约数问题,欧几里德提出了辗转相除算法,其算法思想是:
(1)令m为两个整数中的较大者,n为两个整数中的较小者;
(2)用m除以n,令r为m除以n的余数;
(3)若r不等于0,则令m等于n,n等于r,返回步骤(2)继续;若r等于0,则n中的数值就是两个整数的最大公约数。
从上述算法思想可知,该算法是一个循环过程,并且该循环过程的循环次数事先无法知道,因此,该问题适合于用while语句构造循环过程。
public class Exam2_7
{
public static void main(String args[])
{
int m = 48, n = 32, r = 0, temp;
if(m <= 0 || n <= 0)
{
System.out.println("数据错误!");
return;
}
if(m < n) //保证m >= n
{
temp = m;
m = n;
n = temp;
}
r = m % n; //循环初始化
while(r != 0) //循环条件判断
{
m = n;
n = r;
r = m % n; //循环变量修改
}
System.out.print("最大公约数 = " + n);
}
}
程序运行结果:
最大公约数 = 16
当然,上面程序中的循环过程也可以用for语句构造,用for语句构造循环过程相应的程序段如下:
for(r = m % n; r != 0; r = m % n) //for循环
{
m = n;
n = r;
}
for语句的循环过程中,也必须有循环初始化(r = m % n)、循环条件判断(r != 0)和循环变量修改(r = m % n),只是处于不同的位置而已。显然,在循环次数不知时,用for语句构造的循环过程不及用while语句构造的循环过程清晰。
3.do-while语句
do-while语句的语法形式为:
do
{
<语句组>;
} while (<逻辑表达式>) ;
do-while语句的语义是:首先执行语句组(或称循环体),然后计算<逻辑表达式>的值,当<逻辑表达式>的值为true时,执行一次循环体;当<逻辑表达式>的值为false时,结束循环。
从语义看,do-while语句和while语句的惟一差别是:do-while语句至少执行一次循环体(因其结束条件判断在后面进行);而对于while语句来说,当一开始循环条件就不满足时,循环体将一次也不执行。
例2.7求最大公约数程序的循环部分也可以用do-while语句构造。用do-while语句的相应程序段如下:
r = m % n; //循环初始化
if(r != 0) //判断初始时r是否为0
do
{
m = n;
n = r;
r = m % n; //循环变量修改
} while(r != 0); //循环结束条件判断
由于语句r = m % n的计算结果可能使r等于0,而do语句在第一次执行循环体时,并不做任何判断,这将可能造成因r等于0使n等于0,因n等于0使语句r = m % n的运算出现除数等于0的错误,因此要在do语句之前判断r是否等于0。只有在r不等于0时才执行do语句;在r等于0时最大公约数已经得到。
显然,对于求最大公约数问题,用while语句比用do-while语句简单一些。但在有些情况下,用do-while语句构造循环过程比用while语句简单一些。
4.多重循环
如果循环语句的循环体内又有循环语句,则构成多重循环结构。多重循环结构中的循环语句,可以是前面讨论过的for语句、while语句或do-while语句中的任何一种。
【例2.8】输出九九乘法表。
程序如下:
public class Exam2_8
{
public static void main(String args[])
{
int i,j,n = 9;
for(i = 1; i <= n; i++) //外层循环
{
for(j = 1; j <= i; j++) //内层循环
System.out.print(" " + i*j); //输出
System.out.println(); //每行结束时换行
}
}
}
说明:这个问题中,两重循环的循环次数都已知,因此两重循环都用for语句构造循环过程。外层for语句的循环变量是i,控制总共打印多少行,内层for语句的循环变量是j,控制每行显示多少列。
程序运行结果为:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49
8 16 24 32 40 48 56 64
9 18 27 36 45 54 63 72 81
当应用问题复杂时,程序一般需要有多重循环结构,此时最重要的是要把程序设计的思路梳理清楚,而其中的每一重循环结构都可以按单重循环结构设计。
3、break语句和continue语句
break语句通常是和switch语句或循环语句配合使用,continue语句通常是和循环语句配合使用。
1.break语句
break语句的语法形式是:
break;
在上节讨论switch语句时,我们已结合介绍了switch语句中的break语句使用方法。这里我们主要介绍循环语句中的break语句使用方法。在循环语句中,break语句的功能是跳出循环体。特别需要说明的是,当break语句位于多重循环语句的内层时, break语句只能跳出它当前所处的那层循环体。
【例2.9】循环语句中break语句使用方法示例。
public class Exam2_9
{
public static void main(String args[])
{
int i, j, k;
for(i = 1; i <= 6; i++) //第1层循环
{
for(j = 1; j <= 6; j++) //第2层循环
{
for(k = 1; k <= 6; k++) //第3层循环
{
System.out.println("k = " + k + " ");
if(k == 2) break; //跳出第3层循环
}
System.out.println("j = " + j + " ");
if(j == 2) break; //跳出第2层循环
}
System.out.println("i = " + i + " ");
if(i == 2) break; //跳出第1层循环
}
}
}
由于break语句的作用,此程序的第3层的输出语句(输出k)只执行了8次,第2层的输出语句(输出j)只执行了4次,第1层的输出语句(输出i)只执行了2次。
2.continue语句
continue语句的语法形式为:
continue;
continue语句主要用于循环语句中,continue语句的语义是:若循环体中遇到continue语句,则本次循环体的后续语句被忽略,回到循环条件判断处,判断是否执行下一次循环体。换句话说,continue语句仅跳过当前层循环体的剩余语句。
【例2.10】continue语句使用方法示例。
public class Exam2_10
{
public static void main(String args[])
{
int i, j;
for(i = 1; i <= 6; i++)
{
for(j = 1; j <= 6; j++)
{
if(j >= 3) continue; //continue语句
System.out.println("j = " + j + " ");
}
}
}
}
由于continue语句的作用,第2层的输出语句只执行了12次。
4、return语句
return语句的语法形式为:
return [<返回值>];
return语句的语义是:使函数返回原调用处,且带回返回值。如果函数为void类型,则return语句后没有<返回值>;如果函数为非void类型,则return语句后需要有<返回值>,并且<返回值>的类型必须和函数的类型一致。
当return语句不带<返回值>,并且位于函数的最后时,return语句可以省略。
return语句的具体使用方法可参见随后各章的程序设计举例。
7、程序注释
Java语言允许在程序中添加注释,以增加程序的可读性。前面的例子中已经多次使用了程序注释。注释主要是给人阅读的,所以系统不会对注释的内容进行编译。
Java语言有三种形式的注释:
单行注释 // 注释内容
多行注释 /* ……
多行注释内容
……*/
文件注释 /**……
文件注释内容
*/
8、数组
数组是连续内存单元中一组名字和数据类型相同的数据元素的有限集合。数组可以用来保存和处理一组数据类型相同的数据元素。数组中的每个数据元素称作一个数组元素。
当把一维数组中的每个数据元素定义为一个一维数组时,就构成了Java语言的二维数组,以此类推,还可以有三维数组甚至更多维数组。另外,Java语言可以构造出不规则数组。
1、一维数组
和变量的使用方法类同,一维数组也要先定义后使用,不同的是数组在定义后还要经过内存单元分配后才能使用。
Java语言一维数组的使用分三步:定义一维数组变量、为数组分配内存单元和使用数组元素。
1.一维数组变量定义
一维数组变量定义的语法形式为:
<数据类型><数组名>[];
或
<数据类型>[]<数组名>;
其中,方括号[]表示定义的是数组变量,<数据类型>定义了数组元素的数据类型,<数组名>定义了数组名的标识符。
也可以把数组类型看成是Java语言在基本数据类型的基础上的扩展。
例如:
int[] a;
定义了一个数据类型为int、数组标识符为a的一维数组。
在数组定义后,系统将给数组标识符分配一个内存单元,用于指示数组在内存中的实际存放位置。由于在数组变量定义时,数组元素本身在内存中的实际存放位置还没有给出,所以,此时该数组名的值为空(null)。例如,上述语句执行后数组a的状态如图下图中的(a)所示:
2.为数组分配内存单元
Java语言中,new是一个特殊的运算符。new运算符的语法形式为:
new <数据类型>
new运算符的语义是:向系统申请指定数据类型所需的内存单元空间。new运算符返回所申请内存单元的首地址。
数组元素本身的内存空间必须用new运算符在程序中申请。只有用new运算符为数组分配了内存单元空间后,存放一个数组的所有数组元素所需的内存空间才真正被系统分配了。为数组类型变量分配内存单元的语法形式为:
<数组名> = new <数据类型>[<长度>];
其中,<数组名>必须是已定义的数组类型变量,<数据类型>必须和定义数组名时的数据类型一致,方括号[]内的<长度>指出了当前数组元素的个数。
例如:
a = new int[5];
就具体分配了包含5个int类型数组元素的内存单元,并把该块内存单元的首地址赋值给数组名a
Java语言规定,在数组分配内存单元后,系统将自动给每个数组元素赋初值,并规定:数值类型的数组元素初值为0,逻辑类型的数组元素初值为false,类类型的数组元素初值为null。执行该语句后的示意图如上图中的(b)
3.使用数组元素
一旦完成了定义数组变量和为数组分配内存单元后,就可以使用数组中的任意数组元素。数组元素由数组名、一对方括号、方括号中的整数数值(一般称作下标)组成。其中下标指出了希望操作的数组元素位置。下标由0开始,其最大值为用new运算符分配内存单元时规定的长度值减1。各数组元素在内存中按下标的升序连续存放。上述数组a的5个元素依次是a[0],a[1],a[2],a[3],a[4]。
例如:
a[0] = 10;
语句就给数组元素a[0]赋了数值10。执行该语句后的示意图如上图中的(c)
4.引用类型
前面讨论的用基本数据类型定义变量和这里讨论的定义数组变量有一些不同。用基本数据类型定义的变量,其变量名表示这个变量名中存放的数值,如有下列语句段:
int i, x; //定义变量
i = 10; //给变量i赋值
x = 10 + i; //使用变量i中的数值
上述语句段中,变量i的存储结构如下图中的(a)所示,语句 x = 10 + i中,赋值号右边的变量i表示变量i中的数值10。
对于数组变量,设有下列语句段:
int[] a;
int x;
a = new int[5];
a[0] = 10; //给数组元素a[0]赋值
x = 10 + a[0]; //使用数组元素a[0]中的数值
x = 10 + a; //错误,数值10和数组名 a为不兼容的类型
上述语句段中,数组a的存储结构如上图中的(b)所示,语句 x = 10 + a[0]中,赋值号右边的数组元素a[0]表示数组元素a[0]中的数值,但语句x = 10 + a将出错,因为数组名 a是指向内存中存放数组元素的一片连续内存单元的首地址,所以,数值10和数组名 a为不兼容的类型。
Java语言中,数组名的类型是引用类型。所谓引用类型,是指该类型的标识符表示的是一片内存连续地址的首地址。
引用类型是非常重要的一个概念。下一节要讨论字符串,字符串名和数组名一样,也是引用类型。
5.数组的简化使用方法
数组的定义和为数组分配内存空间两步可以结合起来。
例如:
int a[] = new int[ 5];
就在定义int类型数组变量a的同时为数组分配了5个int类型数组元素所需的内存空间,并给每个数组元素初始赋值0。
数组元素的初始化赋值也可以和上述语句结合在一起完成,此时采用简写形式。例如,
int a[] = {1,2,3,4,5};
就在定义int类型数组变量a、为数组分配了5个int类型数组元素所需的内存空间的同时,初始化给数组元素a[0]赋初值1,a[1]赋初值2,……,a[4]赋初值5
6.数组元素允许的运算
对数组元素可以进行其数据类型所允许的任意运算。
例如:
int u = 3, v = 4, x, y;
int a[] = {1,2,3,4,5};
x = (a[2] + a[3] – u) * v;
y = a[1] / u;
都是合法的表达式。
7.数组的长度
Java语言提供了length成员变量返回数组元素的个数,其使用方法为:
<数组名>.length
例如:
int n;
int a[] = new int[ 10];
n = a.length;
则有n等于10。
8.数组长度的重新定义
一旦为数组规定了长度,在程序中使用数组时就不能超过所规定的长度,否则编译时会给出“数组下标越界”的语法错误。例如,若数组分配的内存空间为5个,则语句中一旦出现a[5]将产生“数组下标越界”的语法错误。
上述情况下,可以用new运算符重新为数组分配内存单元。例如,
a = new int[ 10];
上述语句后,由于重新为数组a分配了10个int类型的内存单元空间,所以,此时若语句中出现a[5],编译时将不会出现“数组下标越界”的语法错误。
【例2.11】求10个数中的最小数。
要求:用数组初始化赋值方法给出10个整数数值。
程序设计如下:
public class Exam2_11
{
public static void main(String args[])
{
int i, min;
int a[] = {30,81,37,45,26,46,44,78,80,64}; //初始化赋值
System.out.print("数组元素为:");
for(i = 0; i < a.length; i++)
System.out.print(" " + a[i]); //输出数组元素
//寻找数组中数值最小的元素
min = a[0];
for(i = 1; i < a.length; i++)
if(a[i] < min) min = a[i];
System.out.println("/n最小数为:" + min);
}
}
程序的运行结果为:
数组元素为: 30 81 37 45 26 46 44 78 80 64
最小数为:26
如果此问题不用数组方法设计,而用简单变量方法设计,程序将非常复杂。因此,数组是复杂问题的程序设计所必需的。
------------------------------------------------------------------------------------------------------
【例2.12】把10个数按从小到大的次序排序。
要求:用数组初始化赋值方法给出10个整数数值,用直接交换排序算法排序。
直接交换排序算法思想:例2.11程序找到的是数组a中的最小数。如果我们在此基础上设计一个循环过程,把每次找到的最小数和数组中尚未排好序的数据元素交换,下次循环时,从这个数据元素的下一个位置开始,继续这样的寻找和交换过程。这样的过程共进行a.length-1次,则全部数组中的数据元素就按从小到大的次序排好了。
程序设计如下:
public class Exam2_12
{
public static void main(String args[])
{
int a[] = {30,81,37,45,26,46,44,78,80,64};
int i, j, min, temp;
System.out.println("排序前数组元素为:");
for(i = 0; i < a.length; i++)
System.out.print(a[i] + " ");
//直接交换排序
for(i = 0; i < a.length-1; i++) //循环a.length-1次
{
min = i;
for(j = i+1; j < a.length; j++)
if(a[j] < a[min]) min = j; //寻找最小数
if(min != i) //判断是否需要交换
{
temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
System.out.println("/n排序后数组元素为:");
for(i = 0; i < a.length; i++)
System.out.print(a[i] + " ");
}
}
程序的运行结果为:
排序前数组元素为:
30 81 37 45 26 46 44 78 80 64
排序后数组元素为:
26 30 37 44 45 46 64 78 80 81
2、二维数组
Java语言只定义了一维数组,但是,如果一维数组的每个数组元素都是一个一维数组,则构成了Java语言的二维数组。和一维数组的使用方法类同,二维数组的使用也分三步:定义数组变量、为数组分配内存单元和使用数组元素。
1.二维数组定义:
二维数组变量定义的一个例子如下:
int a[][];
或
int[] a[];
上面语句定义了一个数据类型为int[](即一维数组类型)、标识符为a的一维数组,即数组a是二维数组。
上述语句执行后数组a的内存状态如下图中的(a)所示:
为二维数组变量分配内存单元时必须指定每一维的数组元素个数。
例如:
a = new int[3][3];
就具体分配了包含3个int[3]类型数组元素的内存单元,并把该连续内存单元的首地址赋给数组名a,同时为每个数组元素初始化赋值0。
上图中的(b)就是上述语句执行后的内存示意图。
使用二维数组元素的方法和使用一维数组元素的方法类同,只是这里要指出二维数组的每一维的下标。例如,语句
a[0][0] = 10;
就给数组元素a[0][0]赋了数值10。如上图(c)所示。
2.二维数组简化:
同样,二维数组也可以用简化方法。例如:
int a[][] = new int[5][5];
就在定义int类型的二维数组变量a的同时,为数组分配了内存单元结构如图2.2(b)所示的5个每一维为int[5]类型数组元素的内存空间,并给每个数组元素初始赋值0。
又例如:
int a[][] = {{1,2,3},{4,5,6},{7,8,9}};
就在定义int类型二维数组变量a、并为二维数组动态分配了9个int类型数组元素内存空间的同时,初始化给数组元素a[0][0]赋初值1,a[0][1]赋初值2,a[0][2]赋初值3,a[1][0]赋初值4,……,a[2][2]赋初值9。
三维数组或更多维数组的使用方法和二维数组的使用方法类同。
【例2.13】求C = A×BT,其中,A是一个行向量,BT是一个列向量,C是一个矩阵。例如,设A和B均为n=3的向量,则矩阵C元素的计算方法是:c11=a1*b1,c12=a1*b2,c13=a1*b3,c21=a2*b1,……,c33=a3*b3。
设计思想:这是一个矩阵运算。用一维数组 a存放行向量A,用一维数组 b存放列向量BT,用两维数组存放矩阵C。
程序设计如下:
public class Exam2_13
{
public static void main(String args[])
{
final int n = 3;
int a[] = {1,2,3};
int b[] = {4,5,6};
int c[][] = new int[n][n];
int i, j;
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
c[i][j] = a[i] * b[j]; //计算cij
System.out.println (”二维数组元素为:”);
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
System.out.print(c[i][j] + " ");
System.out.println();
}
}
}
程序运行输出结果为:
二维数组元素为:
4 5 6
8 10 12
12 15 18
3、不规则的二维数组
由于Java语言的二维数组是由一维数组定义的,所以,可以把二维数组中的每个一维数组定义为不同的元素个数,这样就可以构成不规则的二维数组。
不规则二维数组的具体设计方法是:先定义一个二维数组变量,并指定第一维的元素个数,然后再分别为第二维数组(即第一维数组的每个数组元素)分配不同的内存单元。由于此时是分别为第二维数组分配内存单元,并且第二维数组所分配的内存单元个数可以是不相同的,因此就构成了不规则的二维数组。
例如,下面的代码先定义一个二维数组,并为数组的第一维数组元素分配空间(这就要求必须指定其具体个数),然后再分别为第二维数组元素分配不同的内存空间。
int twoDim [][] = new int [4][]; //定义二维数组,并指定第一维的元素个数
twoDim[0] = new int[1]; //指定第二维第一个元素的个数
twoDim[1] = new int[2]; //指定第二维第二个元素的个数
twoDim[2] = new int[3]; //指定第二维第三个元素的个数
twoDim[3] = new int[4]; //指定第二维第四个元素的个数
数组twoDim得到的内存单元结构如下图所示:
【例2.14】计算并保存九九乘法表,要求重复的部分只保存一个。
设计思想:九九乘法表需要一个二维数组来保存,因为要求重复的部分(如1*2和2*1)只保存一个,所以需要把二维数组定义成不规则的二维数组。
程序设计如下:
public class Exam2_14
{
public static void main(String args[])
{
final int N = 9;
int a[][] = new int [N][]; //定义二维数组,并指定第一维的元素个数
int i,j;
for(i = 0; i < N; i++)
a[i] = new int [i+1]; //指定不规则的第二维的个数
for(i = 0; i < N; i++)
for(j = 0; j <= i; j++)
a[i][j] = (i + 1) * (j + 1); //保存乘法表
//输出乘法表
for(i = 0; i < N; i++)
{
for(j = 0; j <= i; j++)
System.out.print(a[i][j] + " ");
System.out.println();
}
}
}
程序运行输出如下:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49
8 16 24 32 40 48 56 64
9 18 27 36 45 54 63 72 81
9、字符串
字符串是由n(n≥0)个字符组成的序列。为了把一个字符串和别的语言成分区分开来,Java中的字符串用一对双引号括起来,一个字符串中的字符个数称作字符串的长度。如"abc"就是一个长度为3、其值为abc的字符串。
Java中的字符串变量用String来定义,但和char、int等基本数据类型不同的是,String不是一个数据类型,而是一个类。String是Java应用程序接口(即Java API)中定义的一个类。由于应用程序一般要有输出,常用的系统标准输出要求输出参数是一个字符串,因此,本节简单介绍字符串的概念和使用方法。
1.字符串常量
一对双引号括起来的任何字符序列都是一个字符串常量,如""和"sum" 都是字符串常量。字符串常量""的长度为0,字符串常量"sum"的长度为3。
2.字符串变量
定义字符串变量的方法和定义基本数据类型变量的方法类同。如下面语句就定义了两个字符串变量str1和str2:
String str1, str2;
在定义字符串变量时可以同时赋值,例如,下面语句就在定义字符串变量str的同时,给str赋了初值"abc":
String str = "abc";
还可以定义String数组,例如,语句:
String[] v = new String[3];
就定义了一个有3个数组元素的String数组v
3.字符串变量名
和数组名一样,字符串变量名也是引用类型,即字符串变量名是指向内存中一片连续内存单元的首地址。
4.字符串的赋值
字符串变量定义后可以给该变量赋值。例如:
String str;
str = "abc";
上述字符串变量定义和变量赋值也可以写在一个语句中:
String str = "abc";
上述语句的功能是:首先,定义字符串变量str;然后,向系统申请字符类型的长度为3的一片连续内存单元,并把字符’a’、’b’、’c’依次存入内存单元中;最后,把这片连续内存单元的首地址赋给字符串变量名str,即让str指向存放字符串"abc"的内存单元的首地址。
给字符串变量赋值时,还可以赋多个,其方法等同于数组声明时赋值。例如:
String[] v={"Hello world!","Hello China!","Hello XSYU!"};
该语句就给字符串变量v 赋了3个字符串常量值。
5.字符串的连接运算
Java语言提供了特殊的字符串运算符“+”,运算符“+”表示把两个字符串连接起来。例如:
String str = "abc" + "def";
该语句就把字符串值"abcdef",赋给了字符串变量str。
6.标准输出中的字符串
前面已经多次使用了系统的标准输出System.out.print()和System.out.println()。这两个输出语句要求的参数是字符串或字符串表达式。例如,
String str = "abc";
System.out.print("def");
System.out.print(str);
System.out.print(str + "def");
都是合法的输出语句。
前面有如下形式的输出语句:
int j = 10;
System.out.print("j = " + j);
其中,"j = "是一个字符串,j是一个int类型的变量,其数值为10,显然,表达式"j = " + j的数据类型不一致,在这里,系统将把int类型的数值10转换为字符串类型。
因此上面语句将输出:
j = 10