第3章 Java的基本类型程序设计结构
3.1 一个简单的Java应用程序
大小写
- Java区分大小写。
修饰符
- 关键字public称为访问修饰符(access modifier)
- 这些修饰符用于控制程序的其他部分对这段代码的访问级别。
类是容器
- 关键字class表明Java程序中的全部内容都包含在类中。
- 这里,只需要将类作为一个加载程序逻辑的容器,程序逻辑定义了应用程序的行为。
- Java应用程序中的全部内容都必须放置在类中。
命名规则
- 名字必须以字母开头,后面可以跟字母和数字的任意组合。
- 长度基本没有限制。
- 但是不能使用Java保留字。
命名规范
- 类名是以大写字母开头的名词。
- 如果名字由多个单词组成,每个单词的第一个字母都应该大写(驼峰命名法,书中骆驼命名法)。
- 源代码的文件名必须与公共类的名字相同,并用.java作为扩展名。
main方法
- Java虚拟机将从指定类中的main方法开始执行。
- 这里的方法就是Java中所说的“函数”。
- main方法不是public时,有些版本的Java解释器也可以执行Java应用。
- 在Java SE 1.4及以后的版本中强制main方法时public的。
- 所不同的是main方法没有为操作系统返回“退出代码”,如果main方法正常退出,退出代码为0。如果像终止程序返回其他代码,那就要调用System.exit方法。
块
- 用大括号划分程序的各个部分,通常称为块。
- Java中任何方法的代码都用“{”开始,用“}”结束。
方法/函数
- Java中的所有函数都属于某个类的方法,标准术语将其称为方法,而不是成员函数。
分号结束
- 每个句子必须使用分号结束。
- 特别需要说明回车不是语句结束的标志,因此,如果需要可以将一条语句写在多行。(python)
点号调用
- 点号(.)用于调用方法。
分隔字符串
- 采用双引号分隔字符串,单引号是字符。
3.2 注释
三种注释
- 单行注释,可以在每行的注释前面标记//。
- 多行注释,可以使用/*和*/将一段比较长的注释括起来。
- 自动生成文档,以/**开始,以*/结束。
注释嵌套
- 在Java中,/**/注释不能嵌套。
- 会在第一个*/结束注释。
3.3 数据类型
3.3.1 整型
类型 | 储存需求 | 取值范围 |
---|---|---|
int | 4字节 | -2 147 483 648 ~ 2 147 483 647 (正好20亿) |
short | 2字节 | -32 768 ~ 32 767 |
long | 8字节 | -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807 |
byte | 1字节 | -128 ~ 127 |
整数范围
- 在Java中,整型的范围与运行Java代码的机器无关。
- 这解决了软件从一个平台移植到另一个平台。
数值表示
- 十六进制数值有一个前缀0x或0X(如0xCAFE).
- 八进制有一个前缀0,例如010就是8.
- 从Java7开始,加上前缀0b和0B就可以表示二进制数,例如0b1001就是9.
- 同样是Java7开始,还可以为数字字面加下划线,如用1_000_000。这些下划线只是为了让人更易读,Java编译器会去除这些下划线。
字节数量
- 在Java中,所有的数值类型所占据的字节数量和平台无关。
符号数
- Java没有任何无符号数(unsigned)形式的int、long、short或byte类型。
3.3.2 浮点类型
类型 | 储存需求 | 取值范围 |
---|---|---|
float | 4字节 | 大约 ±3.402 823 47E+38F(有效位数为6 ~ 7位) |
double | 8字节 | 大约 ± 1.797 693 134 862 315 70E+308(有效位数为15位) |
使用浮点数
- 绝大部分应用程序都采用double类型。
表示法
- float类型的数值有一个F或f的后缀,例如3.14F.
- 没有后缀F的浮点数值(如3.14)默认为double类型。
- 也可以在浮点数值后面添加后缀D或d,例如3.14D.
浮点数指数表示
- 可以使用十六进制表示浮点数值。
- 在十六进制表示法章,使用p表示指数,而不是使用e。
- 例如,0.125 = 2^-3可以表示成0x1.0p-3
- 注意尾数采用十六进制,指数采用十进制,指数的基数是2,而不是10.
特殊浮点是
- 正无穷大
- 负无穷大
- NaN(不是以恶数字)
特殊浮点数使用
- 错误:if(x == Double,NaN)
- 正确:if(Double.isNaN(x))
- 所有的“非数值”的值都认为是不相同的。
二进制浮点数问题
- (2.0 - 1.1)将打印出0.8999999999999999,而不是人们想象的0.9.
- 原因是浮点数值采用二进制系统表示,无法精确表示分数1/10,和十进制的1/3一样。
- 如果数值计算中不允许有任何舍入误差,就应该使用BigDecimal类。
3.3.3 char类型
表示
- 有些Uinicode字符可以使用一个char值描述。
与字符串区别
- ‘A’是编码值为65所对应的字符常量。
- “A”是包含一个字符A的字符串。
范围
- char类型的值可以表示为十六进制值,其范围从\u0000到\uffff.
转义序列
转义序列 | 名称 | Unicode值 |
---|---|---|
\b | 退格 | \u0008 |
\t | 制表 | \u0009 |
\n | 换行 | \u000a |
\r | 回车 | \u000d |
\" | 双引号 | \u0022 |
\’ | 单引号 | \u027 |
\\ | 反斜杠 | \u005c |
注意转义语法
- Unicode转义序列会在解析代码之前得到处理。
- “\u0022+\u0022"并不是一个由引号(U+0022)包围加号构成的字符串。实际上会得到”“+”“的空串。
- //\u0A0 is a newline,程序的时\u0A0会替换为一个换行符,产生一个语法错误。
- // Look inside C:\users,也会产生一个语法错误,因为\u后面未跟着4个十六进制数。
3.3.4 Unicode和Char类型
Unicode解决问题
- 对于任意给定的代码值,在不同的编码方案下有可能对应不同的字母。
- 采用大字符集的语言其编码长度可能不同。(例如,有些字符采用单字节编码,而另一些字符这需要两个或更多个字节)。
时间
- 从Java SE 5.0 开始。
码点(code point)
- 是指与一个编码表中的某个字符对于的代码值。
**代码级别(code plane)
- Unicode的码点可以分成17个代码级别。
多语言级别(basic multilingual plane)
- 第一个代码级别称为基本的多语言级别。
- 码点从U+0000到U+FFFF.
辅助字符(supplementary character)
- 其余的16个级别从U+10000到U+10FFFF,其中包括一些辅助字符。
代码单元(code uint)
- 在基本的多语言级别中,每个字符用16位表示,通常被称为代码单元。
- 而辅助字符采用一对连续的代码单元进行编码。
辅助字符编码
- 辅助字符采用一对连续的代码单元进行编码。
- 这样构成的编码值落入基本的多语言级别中空闲的2048字节内,通常被称为**替换区域(surogate plane).
- U+D800 ~ U+DBFF用于第一个代码单元,U+DC00 ~ U+DFFF用于第二个代码单元。
- 在Java中,char类型描述了UTF-16编码中的一个代码单元。所以两个char类型才能表示辅助字符?
3.3.5 boolean类型
- boolean(布尔)类型有两个值:true和false。
3.4 变量
类型
- 在Java中每个变量都有一个类型(type)。
- 在声明变量时,变量的类型位于变量名之前。
声明
- 声明是一条完整的Java语句。
- 必须以分号结束。
命名规则
- 变量名必须是一个以字母开头并由字母和数字构成的序列。
- 需要注意,与大多数程序设计语言相比,Java中的“字母”和“数字”的范围更大。
- 变量名中所有字符都是有意义的,并且大小写敏感。
- 变量名在长度上基本没有限制。
- 不能使用Java保留字作为变量名。
字母范围
- ‘A’ ~ ‘Z’、‘a’ ~ ‘z’、’_’、’$’
- 或某种语言中表示字母的任何Unicode字符。
数字氛围
- ‘0’ ~ ‘9’
- 和某种语言中表示数字的任何Unicode字符。
例外字符
- ‘+’、‘©’、空格
字母检擦
- 可以使用Character类的isJavaIdentifierStart和isJavaIdentiferPart方法来检擦。
注意’$'符号
- 尽管’$'是一个合法的Java字符,但不要在你自己的代码中使用这个字符。
- 它只用在Java编译器或其他工具生成的名字中。
3.4.1 变量的初始化
初始化
- 声明一个变量后,必须用赋值语句对变量进行显式初始化。
- 千万不要使用未初始化的变量。
声明和定义
- C和C++区分声明和定义。
- int i = 10; 是一个定义。
- extern int i; 是一个声明。
3.4.2 常量
常量
- 在Java中,利用关键字final指示常量。
- 关键字final表示这个变量只能被赋值一次。(是否可以先声明后赋值?)
- 一旦赋值之后,就不能够再更改了。
- 习惯上,常量名使用全大写。
final赋值问题
- final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
- 类常量(static final)必须在声明时初始化。
- 本地变量必须在声明时赋值,因为没有初始化过程。
类常量
- 希望某个常量可以在一个类中的多个方法中使用。
- 类常量的定义位于main方法的外部。
const关键字
- const是Java保留的关键字,但是目前没有使用。
3.5 运算符
运算符
- 在Java中,使用算术运算符+、-、*、/表示加、减、乘、除运算。
stricfp关键字
- 在默认情况下,虚拟机设计者允许对中间计算结果采用扩展的精度。
- 但是对于使用strictfp关键字标记的方法必须使用严格的浮点计算生成可再生的结果。
3.5.1 数学函数与常量
平方根函数
- Math.sqrt(x),对x求平方根。
幂运算
- Math.pow(x, a), x的a次幂,x^a。
负数求余
- floorMod(position + adjustment, 12)
- ((position + adjustment) % 12 + 12) % 12
- 总会得到一个0 ~ 11之间的数,但对于负除数会得到负数结果。
三角函数
- Math.sin
- Math.cos
- Math.tan
- Math.atan
- Math.atan2
指数函数和其反函数
- Math.exp
- Math.log
- Math.log10
常量近似值
- Math.PI
- Math.E
StrictMath
- 如果得到一个完全可以预测的结果比运行速度更重要的话,那么就应该使用StrictMath类
3.5.2 数值类型之间的转换
数值转换
- 如果两个操作数中有一个时double类型,另一个操作数就会转换成double类型。
- 否则,如果其中一个操作数时float类型,另一个操作数将会转换为float类型。
- 否则,如果其中一个操作数时long类型,另一个操作数将会转换为long类型。
- 否则,两个操作数都将转换为int类型。
3.5.3强制类型转换
强制类型转换
- 在Java中,允许进行数值之间的类型转换,但是可能会丢失一些信息。
- 例如:double x = 9.997; int nx = (int) x;
舍入运算
- 如果想对浮点数进行舍入运算,以便得到最接近的整数,那就需要使用Math.round方法。
- 例如,double x = 9.997; int nx = (int) Math.round(x)
- 注意调用时需要使用强制转换,因为round方法返回的结果为long类型。
数据截断
- 如果试图将一个数值从一种类型强制转换成另一种类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不同的值。
- 例如,(byte)300的实际值为44.
3.5.4 结合赋值和运算符
二元运算符
- 可以在赋值中使用二元运算符。
- +=、-=、*=、/=、%=
注意类型转换
- 如果运算符得到一个值,其类型与左侧操作数的类型不同,就会发生强制类型转换。
- 例如,int x += 3.5等价于(int) (x + 3.5)。
3.5.5 自增和自减运算符
两种形式
- 运算符放在操作数的后面的“后缀形式”,还有一种前缀形式。
- 前缀会先完成+1,而后缀会使用变量原来的值。
3.5.6 关系和boolean运算符
- 使用 == 检测相等性,使用 != 检测不相等。
- <(小于)、>(大于)、<=(小于等于)、>=(大于等于)。
- && 表示逻辑“与”运算符,|| 表示逻辑“或”运算符。
注意&&和||的求值
- &&和||运算符是按“短路”的方式来求值的。
- 如果一个操作数已经能够确定表达式的值,第二个操作数就不必计算了。
三元操作符
- 对于 condition ? expression1 : expression2
- 如果condition为true,就为第一个表达式的值,否则计算第二个表达式的值。
3.5.7 位运算符
位运算符
- &(and)、|(or)、^(xor)、~(not)
和"&&“以及”||"的区别
- 应用在布尔值上时,&和|运算符也会得到一个布尔值。
- &和|运算符不采用"短路"的方式来求值,也就是说,得到计算结果之前两个操作数都需要计算。
左移和右移
- >>和<<运算符将位模式左移或右移。
注意>>>运算符
- >>>运算符会用0填充高位,这与>>不同,它会用符号位填充高位。
- 不存在<<<运算符。
注意右边值
- 移位运算符的右操作数要完成模32的运算(除非左操作数时long类型,在这种情况下需要对左操作数模64).
- 例如,1<<35的值等同于1<<3或8。
3.5.8 括号和运算符级别
运算符 | 结合型 |
---|---|
[].()(方法调用) | 从左到右 |
!~+±-+(一元运算)-(一元运算)()(强制类型转换)new | 从右到左 |
*/% | 从左到右 |
± | 从左到右 |
<< >> >>> | 从左到右 |
< <= > >= instanceof | 从左到右 |
== != | 从左到右 |
& | 从左到右 |
^ | 从左到右 |
| | 从左到右 |
&& | 从左到右 |
|| | 从左到右 |
?: | 从右到左 |
= += -= *= /= %= &= |= ^= <<= >>= >>>= | 从右到左 |
运算优先级
- 如果不使用圆括号,就按照给出的运算符优先级次序进行计算。
- 同一级别的运算符按照从左到右的次序进行计算。
- 除表中给出的右结合运算符外。
举例
- +=是右结合运算符,a += b += c 等价于a += (b += c)。
逗号,的使用
- Java不使用逗号运算符。
- 可以在for语句的第一和第三部分使用逗号分隔表达式列表。
- &&的优先级比||高,a && b || c等价于(a && b) || c.
枚举类型
解决问题
- 有时候,变量的取值在一个有限的集合内。
- 在变量中很可能保存的是一个错误的值。
储存范围
- 枚举类型只能这个类型声明中给定的某个枚举值,或者null值,null表示这个变量没有设置任何值。
3.6 字符串
字符串是对象
- Java中没有内置的字符串类型,而是在标准Java库类中提供了一个预定义类,很自然的叫做String。
- 每个用双引号括起来的字符串都是String 类的一个实例。
3.6.1 子串
substring方法
- String类的substring方法可以从一个较大的字符串提取出一个子串。
- substring方法的第二个参数是不想复制的第一个位置。
- 优点:容易计算子串的长度。
- 字符串s.substring(a,b)的长度为b-a。(左闭右开)
3.6.2 拼接
**字符串拼接*8
- Java语言允许使用+号连接(拼接)两个字符串。
- 当将一个字符串与一个非字符串拼接时,后者被转换成字符串。
- 如果需要使用多个字符串放在一起,用一个定界符分隔,可以使用静态join方法。
- 举例:string all = String.join("/",“S”,“M”,“L”,“XL”);//all is the string “S/M/L/XL”
3.6.3 不可变字符串
字符串不修改
- String类没有提供用于修改字符串的方法。
- 解决:首先提取要的字符串,然后再拼接上替换的字符串。
- 例如,greeting = greeting.substring(0,3) + “p!”;
不可变字符串优点
- 编译器可以让字符串共享。
- Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。
- 查看一下程序会发现:很少需要修改字符串,而是往往需要对字符串进行比较。
替换实际操作
char* temp = malloc(6)
strncopy(temp, greeting, 3);
strncopy(temp + 3, “p!”, 3);
greeting = temp;
3.6.4 检测字符串是否相等
检查字符串相等
- 可以使用equals方法检测两个字符串是否相等。
- 要想检测两个字符串是否相等,而不区分大小写,可以使用equalsIgnoreCase方法。
- 注意:一定不要使用==运算符检测两个字符串是否相等!这个运算符能够确定连个字符串是否被放置在同一个位置上。
注意==运算符
- 如果虚拟机始终将相同的字符串共享,就可以使用==运算符检测是否相等。但实际上只有字符串常量是共享的,而+或substring等操作产生的结果并不是共享的。
- C++的string类重载了==运算符以便检测字符串内容的相等性。(注意不是C语言)
String的compareTo方法
- Java的compareTo方法与strcmp方法类型。
- 例如,if(greeting.compareTo(“hello”) == 0)。
3.6.5 空串和Null串
空串
- 空串是一个Java对象,有自己的长度(0)和内容(空)。
空值Null
- String变量还可以放一个特殊的值,名为null,这表示没有任何对象与该变量关联。
检查字符串为空
- TextUtil.IsEmpty(…)。
3.6.6 码点与代码单元
- char类型是一个采用UTF-16编码表示Unicode码点的代码单元。
- 大多数的常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。
字符串长度相关
- length方法将返回采用UTF-16编码表示的给定字符串所需要的代码单元数量。
int n = greeting.lenth();
- codePointCount方法可以得到实际长度,即码点数量。
int cpCount = greeting.codePointCount(0,greeting.length());
- charAt(n)将返回位置n的代码单元,n介于0~s.length - 1之间。
char first = greeting,charAt(0);
- 想要得到第i个码点,应该使用下列语句。
int index = greeting.offsetByCodePoint(0,i);
int cp = greeting.codePointAt(index);
遍历码点
- 使用codePoints方法,它会生成一个int值的"流",每个int值对应一个码点。
- 要把一个码点数组转换为一个字符串,可以使用构造函数。
int[] codePoints = str.codePoints().toArray();
String str= new String(codePoints,0,lenth);
3.6.7 String API
3.6.8 阅读联机API文档
API文档
- API文档是JDK的一部分,它是HTMl格式的。
- 让浏览器指向安装JDK的docs/api/index.html子目录就可以查看。
3.6.9 构建字符串
解决构建效率问题
- 每次连接字符串,都会构建一个新的String对象,既耗时,又浪费空间。
- 使用StringBuilder类就可以避免这个问题的发生。
StringBuilder类
- 当每次需要添加一部分内容时,就调用append方法。
- 在需要构建字符串时就调用toString方法,将可以得到一个String对象。
- 在JDK5.0时代引入的StringBuilder类。
- 这个类的前身是StringBuffer,其效率稍微有些低,但允许采用多线程的方式执行添加或删除字符的操作。
3.7 输入输出
3.7.1 读取输入
标准输出流
- 只要调用System.out.println即可。
标准输入流
- 想要通过控制台进行输入,首先需要构造一个Scanner对象,并与"标准输出流"System.in关联。
Scanner in = new Scannner(System.in);
读取方法
- 使用nextLine方法是因为在输入行中有可能包含空格。
- 要想读取一个单词(以空白符作为分隔符),可以调用in.next方法。
- 想要读取一个整数,就调用nextInt方法。
读取密码
- Scanner类不适用从控制台读取密码。
- Java SE 6特别引入了Console类实现这个目的。
Console cons = System.console();
String username = cons.readLine(“User name:”);
char[] passwd = cons.readPassword(“Password:”);
3.7.2 格式化输出
- 庆幸的是,Java SE 5.0沿用了C语言库函数的printf方法。
- 例如:
System.out.printf("%8.2f",x);
格式说明符
- 每一个以%字符开头的格式说明符都用相应的参数替换。
- 格式说明符尾部的转换符将被格式化数值的类型:f表示浮点数,s表示字符串,d表示十进制数。
用于printf的转换符
转换符 | 类型 | 举例 |
---|---|---|
d | 十进制数 | 159 |
x | 十六进制数 | 9f |
o | 八进制数 | 237 |
f | 定点浮点数 | 15.9 |
e | 指数浮点数 | 1.59c+01 |
g | 通用浮点数 | - |
a | 十六进制浮点数 | 0x1.1fccdp3 |
s | 字符串 | Hello |
c | 字符 | H |
b | 布尔 | Time |
h | 散列码 | 42628b2 |
tx或Tx | 日期时间(T强制大写) | 已经过时,应当改为使用java.time类 |
% | 百分号 | % |
n | 与平台有关的行分隔符 | - |
用于printf的标志
标志 | 目的 | 举例 |
---|---|---|
+ | 打印正数和负数的符号 | +3333.33 |
空格 | 在正数之间添加空格 | | 3333.33| |
0 | 数字前面补0 | 003333.33 |
- | 左对齐 | |3333.33 | |
( | 将负数添加在括号内 | (3333.33) |
, | 添加分组分隔 | 3,333.33 |
#(对于f格式) | 包含小数点 | 3,333. |
#(对于x和0格式) | 添加前缀0x或0 | 0xcafe |
$ | 给定被格式化的参数索引。例如,%1 d , d,%1 d,x将以十进制和十六进制打印第一个参数 | 159.F |
< | 格式化前面说明的数值。例如,%d%<x以十进制和十六进制打印同一个数值 | 159.9F |
参数索引起始
- 参数索引值从1开始,而不是从0开始。
格式化其他对象到字符串
- 可以使用s转换符格式化任意对象。
- 对于任意实现了Formattable接口的对象都将调用formatTo方法。否则将调用toString方法。
格式化日期和时间(已废弃)
- 例如:
system.out.printf("%tc",new Date());
//Mon Feb 09 18:05:19 PST 2015
格式说明符语法
3.7.3 文件输入输出
文件输入
- 想要对文件进行读取,就需要一个用File对象构造一个scanner对象。
- 如果文件名中包含反斜杠符号,就要记住在每个反斜杠之前再加一个额外的反斜杠:“ c:\mydirectory\myfile.txt ” 。
Scanner in = new Scanner(Paths.get(“niyflle.txt”), “UTF-8”);
文件输出
-
要想写入文件, 就需要构造一个 PrintWriter 对象。在构造器中,只需要提供文件名:
PrintWriter out = new PrintlulriterC’myfile.txt", “UTF-8”);
-
如果文件不存在,创建该文件。可以像输出到 System.out一样使用print、println以及printf命令。
注意scanner字符串参数
- 可以构造一个带有字符串参数的 Scanner, 但这个Scanner 将字符串解释为数据,而不是文件名。
Scanner in = new Scannerrmyfile.txt"); // ERROR?
输入异常
- 如果用一个不存在的文件构造一个 Scanner,或者用一个不能被创建的文件名构造一个 PrintWriter,那么就会发生异常。
3.8 控制流程
3.8.1 块作用域
块的定义
- 块(即复合语句)是指由一对大括号括起来的若干条简单的 Java 语句。块确定了变量的作用域。一个块可以嵌套在另一个块中。
块的嵌套变量
- 但是,不能在嵌套的两个块中声明同名的变量。
public static void main(String口 args) {
int n;
{
int k;
int n; // Error can't redefine n in inner block
}
}
注意和C++的区别
- 在 C++ 中, 可以在嵌套的块中重定义一个变量。在内层定义的变量会覆盖在外层定义的变量。
3.8.2 条件语句
- if语句
- if/else语句
- if/else if (多分支)
if (condition) statement
if (condition) statementi else statementi
if (condition1) statementi else if (condition2) statement2 …
3.8.3 循环
- while 语句
- do/while 循环语句
while { condition ) statement
do statement while (condition);
3.8.4 确定循环
for循环步骤
- for 语句的第 1 部分通常用于对计数器初始化;第 2 部分给出每次新一轮循环执行前要检测的循环条件;第 3 部分指示如何更新计数器。
注意for循环变量范围
- 如果在 for 语句内部定义一个变量, 这个变量就不能在循环体之外使用。
3.8.5 多重选择:switch语句
switch语句
- switch语句将从与选项值相匹配的 case 标签处开始执行直到遇到 break 语句,或者执行到switch i吾句的结束处为止。如果没有相匹配的 case 标签, 而有 default 子句, 就执行这个子句。
- 有可能触发多个 case 分支。 如果在 case 分支语句的末尾没有 break 语句, 那么就会接着执行下一个 case 分支语句。
注意case的标签
- 类型为 char、byte、 short 或 int 的常量表达式。
- 枚举常量。
- 从 Java SE 7开始,case 标签还可以是字符串字面量。
枚举标签的简化
- 当在 switch 语句中使用枚举常量时,不必在每个标签中指明枚举名,可以由 switch 的表达式值确定。
Size sz = ...;
switch (sz) {
case SMALL: // no need to use Size.SMALL
...
break;
...
}
3.8.6 中断控制流程语句
- break语句
- continue语句
关于goto语句
- 尽管 Java 的设计者将 goto 作为保留字,但实际上并没有打算在语言中使用它。
带标签的break语句
- 与 C++ 不同,Java 还提供了一种带标签的 break语句,用于跳出多重嵌套的循环语句。
- 请注意,标签必须放在希望跳出的最外层循环之前, 并且必须紧跟一个冒号。
- 另外需要注意,只能跳出语句块,而不能跳入语句块。
read_data:
while (. . .) // this loop statement is tagged with the label
{
...
for (. . .) // this inner loop is not labeled
{
Systen.out.print("Enter a number >= 0: ");
n = in.nextlntO;
if (n < 0) // should never happen-can’t go on
break read.data;
// break out of readjata loop
...
}
}
更多使用
- 可以将标签应用到任何语句中, 甚至可以应用到 if语句或者块语句中,
如下所示:
label:
{
if (condition) break label ] // exits block
...
}
// jumps here when the break statement executes
continue语句
- continue语句将控制转移到最内层循环的首部。
- 还有一种带标签的 continue 语句,将跳到与标签匹配的循环首部。
3.9 大数值
大数值类
- Biglnteger 和 BigDecimaL 这两个类可以处理包含任意长度数字序列的数值。
- Biglnteger 类实现了任意精度的整数运算, BigDecimal 实现了任意精度的浮点数运算。
使用方法
- 不能使用人们熟悉的算术运算符(如:+ 和 *) 处理大数值。而需要使用大数值类中的 add 和 multiply 方法。
Java运算符重载
- Java 语言的设计者确实为字符串的连接重载了 + 运算符,但没有重载其他的运算符,也没有给 Java 程序员在自己的类中重栽运算符的机会。
3.10 数组
数组定义
- 数组是一种数据结构, 用来存储同一类型值的集合。
数组创建
- 应该使用 new 运算符创建数组。
int[] a = new int[100];
注意长度不要求常量
- 数组长度不要求是常量: newint[n] 会创建一个长度为 n 的数组。
两种声明方式
- int[] a;
- int a口;
- 大多数 Java 应用程序员喜欢使用第一种风格, 因为它将类型 int[] ( 整型数组)与变量名分开了。
数组元素初始化
- 创建一个数字数组时, 所有元素都初始化为 0。
- boolean 数组的元素会初始化为 false。
- 对象数组的元素则初始化为一个特殊值 null, 这表示这些元素(还)未存放任何对象。
注意数组越界
- 如果创建了一个 100 个元素的数组,并且试图访问元素 a[100] (或任何在 0 ~ 99之外的下标), 程序就会引发“ array index out of bounds” 异常而终止执行。
注意数组大小不可变
- 一旦创建了数组, 就不能再改变它的大小(尽管可以改变每一个数组元素)。
3.10.1 for each 循环
for each 语法格式
for (variable : collection) statement
for each要求
- collection 这一集合表达式必须是一个数组或者是一个实现了 Iterable 接口的类对象(例如ArrayList)。
列外情况
- 在很多场合下, 还是需要使用传统的 for 循环t 例如,如果不希望遍历集合中的每个元素, 或者在循环内部需要使用下标值等。
数组打印方法
- 即利用 Arrays 类的 toString 方法。 调用 Arrays.toString(a), 返回一个包含数组元素的字符串。
3.10.2 数组初始化以及匿名数组
创建时初始化
- 在 Java中, 提供了一种创建数组对象并同时赋予初始值的简化书写形式。
int[] small Primes = { 2, 3, 5, 7, 11, 13 };
匿名数组
new intD { 17, 19, 23, 29, 31, 37 }
- 这种表示法将创建一个新数组并利用括号中提供的值进行初始化,数组的大小就是初始值的个数。
- 使用这种语法形式可以在不创建新变量的情况下重新初始化一个数组。
匿名函数实际过程
intD anonymous = { 17, 19, 23, 29, 31, 37 };
smallPrimes = anonymous;
注意数组长度可为0
- 在 Java 中, 允许数组长度为 0。
- 在编写一个结果为数组的方法时, 如果碰巧结果为空, 则这种语法形式就显得非常有用。
- 注意, 数组长度为 0 与 null 不同。
3.10.3 数组拷贝
一般拷贝
- 在 Java 中,允许将一个数组变量拷贝给另一个数组变量。这时, 两个变量将引用同一个数组。
intQ luckyNumbers = smallPrimes;
1uckyNumbers[S] = 12; // now smallPrimes[5] is also 12
赋值拷贝
- 如果希望将一个数组的所有值拷贝到一个新的数组中去,就要使用 Arrays 类的 copyOf方法:
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers , luckyNumbers .length);
增加数组长度
luckyNumbers = Arrays.copyOf(luckyNumbers , 2 * luckyNumbers.length);
- 数组元素是数值型,那么多余的元素将被赋值为 0 ; 如果数组元素是布尔型,则将赋值为 false。
- 相反,如果长度小于原始数组的长度,则只拷贝最前面的数据元素。
3.10.4 命令行参数
命令行参数
- 每一个 Java 应用程序都有一个带 String arg[]参数的 main 方法。
- 这个参数表明 main 方法将接收一个字符串数组, 也就是命令行参数。
public class Message {
public static void main(String[] args) {
if (args.length = 0 11 args[0].equals("-h"))
System.out.printCHello,");
else if (args[0].equa1s("-gM))
System.out.print("Goodbye ,");
// print the other command-line arguments
for (int i = 1; i < args.length; i ++)
System.out.print(" " + args[i]);
System.out.println("!");
}
}
如果使用下面这种形式运行这个程序:
java Message -g cruel world
args 数组将包含下列内容:
args[0]:"-g"
args[l]:“cruel”
args[2]:“world”
这个程序将显示下列信息:
Goodbye, cruel world!
注意程序名
- 在 Java 应用程序的 main 方法中, 程序名并没有存储在 args 数组中u。
3.10.5 数组排序
数组排序
- 要想对数值型数组进行排序, 可以使用 Arrays 类中的 sort 方法:
int[] a = new int[10000];
Arrays.sort(a)
3.10.6 多维数组
多维数组
- 多维数组将使用多个下标访问数组元素, 它适用于表示表格或更加复杂的排列形式。
二维数组打印
System.out.println(Arrays.deepToString(a));
3.10.7 不规则数组
多维数组实质
- Java 实际上没有多维数组,只有一维数组。多维数组被解释为“ 数组的数组。”
不规则数组
- 还可以方便地构造一个“ 不规则” 数组, 即数组的每一行有不同的长度。
注意二维数组指针实质
doublet][] balances = new double[10][6]; // java
不同于
double balances [10] [6]; // C++
也不同于
double (balances)[6] = new double[10] [6]; // C++
而是分配了一个包含 10 个指针的数组:
double* balances = new double*[10]; // C++
然后, 指针数组的每一个元素被填充了一个包含 6 个数字的数组:
for (i = 0; i < 10; i++)
balances[i] = new double [6] ;
庆幸的是, 当创建 new double[10][6] 时, 这个循环将自动地执行。当需要不规则的数组时,只能单独地创建行数组。