3: Controlling Program Flow(控制程序流程)

使用Java运算符
几乎所有的运算符都只能作用于primitive。但是‘=’,‘==’,以及‘!=’是例外,它们可以作用于任何对象(由此也是对象方面一个很让人头晕的问题。)此外,String类也支持‘+’和‘+=’。
优先级
赋值

primitive赋值的时候,是将内容从一个地方直接拷贝到另一个地方。
操控对象就得通过reference来进行操作。当你“在对象之间”进行赋值得时候,实际上你是在拷贝它得reference。
方法调用期间的aliasing
数学运算符
正则表达式(Regular expressions)
单元的加号和减号运算符
自动递增与递减
对于前置递增和前置递减,(也就是++a和--a),操作过程是会先计算再返回。对于后置递增和后置递减,(也就是a++和a--),操作步骤是先返回再计算。
关系运算符
测试对象的相等性

==和!=比较的是对象的reference。要想比较这两个对象的实际内容,必须使用每个类都有的,专门的equals()方法(primitives没有,因为==和!=就用得很好)。
equals()的缺省行为是比较reference。
逻辑运算符
短接
位运算符

位运算符可以与=连起来用,以表示同时进行计算和赋值:&=,|=和^=都是合法的。(至于~,它既然是一个单元运算符,也就不需要同=绑在一起了。)
Boolean类型会被当作只有一位的值,所以它多少有点不同。你可以进行与,或,以及异或运算,但是不能进行非运算(可能是为了防止同逻辑非相混淆)。对于boolean,位运算用逻辑运算的在功能上是相同的,只是它没有短接。此外boolean的位运算里有一个逻辑运算所没有的异或。
移位运算符
它只能用于整数型的primitive数据。
三元if-else运算符
逗号运算符
Java里面,唯一一个把逗号当运算符用的地方是for循环。
String的+运算符
常见的使用运算符方面的错误
类型转换运算符

碰到所谓的narrowing conversion的时候(也就是说,当你将一个能保存较多信息的数据类型,转换成一个保存不了这么多信息的数据类型时),它会产生一个异常。编译器会强制你明确地进行转换,实际上它的潜台词是“这么做可能很危险——如果你一定要做,那么请明确地告诉我”。
对于widening conversion,就不必进行显式转换了,因为新类型可以存储比旧类型更多的信息,所以什么都丢不了。
Java允许你对除boolean之外的其它primitive类型的数据进行任意的转换,而boolean则根本不能转换。
类是不允许转换的。要让他们相互转换,必须要有特殊的方法。(String是一个特例。此外,所有对象都可以在它的类系(family of types)里面上下传递。)
常量(Literals)
C,C++或者Java里面都没有两进制常量值的表示方法。
跟在常量值后面的那个数字表明了它的类型。大写或者小写的L表示long,大写或者小写的F表示float,而大写或者小写的D表示double。
编译器通常会把用指数表示的数字当成double,所以在给float赋值如果没有后缀的f的话,它就会给你一个错误信息,告诉你你必须将double转换成float。
提升
Java没有“sizeof”
重访优先级
Ulcer Addicts Really Like C A lot.

Mnemonic

Operator type

Operators

Ulcer

Unary

+ - ++--

Addicts

Arithmetic(and shift)

* / % + - << >>

Really

Relational

> < >= <= == !=

Like

Logical(and bitwise)

&& || & | ^

C

Conditional(ternary)

A > B? X: Y

A Lot

Assignment

=(and compound assignment like *=)

运算符的总结
boolean的限制性是很强的。你只能赋给它true和false这两个值,而且只能测试它的真或假,你不能把boolean值加起来,或者进行其它什么操作。
进行数学运算的时候,char,byte,以及short,都会先进行提升,而运算结果也是int,因此如果想把它赋还给原先那个变量的话,旧必须明确地进行类型转换(属于会丢失信息的narrowing conversion)。

执行控制
true和false
if-else
return
循环语句
do-while
while与do-while的唯一区别就是,即使第一次判断的结果是false,do-while的statement也会至少运行一次。
for
for循环通常被用于“计数”的任务。
你可以在for语句里定义多个变量,但必须是相同类型的。
只有for语句才有在“控制表达式”里定义变量的能力。千万别在其它选择语句或循环语句里这么做。
逗号运算符
break和continue

break会忽略尚未执行的循环代码,并且退出循环。
continue会跳过尚未执行的代码,中断本次循环,再进入下一周期的循环。
臭名昭著的“goto”
在Java里,唯一能放标签的地方,就是在循环语句的外面。而且必须直接放——循环语句和标签之间不能有任何东西。而这么做的唯一理由就是,你会嵌套多层循环或选择。因为通常情况下break和continue关键词只会中断当前循环,而用了标签之后,它就会退到label所在的地方。
1. 普通的continue会退到内部循环的最开始,然后继续执行内部循环。
2. 带标签的continue会跳转到标签,并且重新进入直接跟在标签后面的循环。
3. break会从循环的“底部溜出去”。
4. 带标签的break会从由这个标签标识的循环的“底部溜出去”。
在Java里,能让你使用标签的唯一理由就是,在嵌套循环的同时还要用break和continue退出多层循环。
switch
在case语句里,单引号括起来的字符在用于比较的时候,会返回整数值。
计算细节
将float或double转换成整数的时候,它总是将其后面的小数截去。
Math.random()会生成0.0,或者用数学术语,它的值域是[0,1)。

总结

练习

「读书笔记」Thinking in Java 3rd Edition - 4: Initialization & Cleanup