在Java里,我们利用运算符操纵对象和数据,并用执行控制语句作出选择。
1.使用Java运算符
所有运算符都能根据自己的运算对象生成一个值。除此以外,一个运算符可改变运算对象的值,这叫作“副作用”(Side Effect)。
几乎所有运算符都只能操作“基本类型”(Primitives)。唯一的例外是“=”、“==”和“!=”,它们能操作所有对象(也是对象易令人混淆的一个地方)。除此以外,String类支持“+”和“+=”。
1.1 优先级
运算符的优先级决定了存在多个运算符时一个表达式各部分的计算顺序。
1.2 赋值
对基本数据类型的赋值是非常直接的。
但在为对象“赋值”的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是它的句柄。所以倘若“从一个对象到另一个对象”赋值,实际就是将句柄从一个地方复制到另一个地方。这意味着假若为对象使用“C=D”,那么C和D最终都会指向最初只有D才指向的那个对象。
将一个对象传递到方法内部时,也会产生别名现象。
1.3 算术运算符
加号(+)、减号(-)、除号(/)、乘号(*)以及模数(%,从整数除法中获得余数)。
一元加、减运算符。
x = a * (-b);
1.4 自动递增和递减
1.5 关系运算符
小于(<)、大于(>)、小于或等于(<=)、大于或等于(>=)、等于(==)以及不等于(!=)。
- =和!=比较的正好就是对象句柄。
- 若想对比两个对象的实际内容是否相同,又该如何操作呢?此时,必须使用所有对象都适用的特殊方法equals()。但这个方法不适用于“基本类型”,那些类型直接使用==和!=即可。
- 假设您创建了自己的类
这是由于equals()的默认行为是比较句柄。所以除非在自己的新类中改变了equals(),否则不可能表现出我们希望的行为。但要注意equals()的这种行为方式同时或许能够避免一些“灾难”性的事件。
大多数Java类库都实现了equals(),所以它实际比较的是对象的内容,而非它们的句柄。
1.6 逻辑运算符
AND(&&)、OR(||)以及NOT(!),只可将AND,OR或NOT应用于布尔值。
- 操作逻辑运算符时,我们会遇到一种名为“短路”的情况。
1.7 按位运算符
& | ^ ~
1.8 移位运算符(技术细节待验证)
<< >> >>>无符号右移
1.9 三元if-else运算符
1.10 逗号
在Java里需要用到逗号的唯一场所就是for循环。
1.11 字串运算符+
1.12 运算符常规操作规则
1.13 造型运算符
- 字面值
最开始的时候,若在一个程序里插入“字面值”(Literal),编译器通常能准确知道要生成什么样的类型。但在有些时候,对于类型却是暧昧不清的。若发生这种情况,必须对编译器加以适当的“指导”。 - 转型
大家会发现假若对主数据类型执行任何算术或按位运算,只要它们“比int小”(即char,byte或者short),那么在正式执行运算之前,那些值会自动转换成int。
表达式中最大的数据类型是决定了表达式最终结果大小的那个类型。若将一个float值与一个double值相乘,结果就是double;如将一个int和一个long值相加,则结果为long。
大家可以看到,除boolean以外,任何一种主类型都可通过造型变为其他主类型。同样地,当造型成一种较小的类型时,必须留意“缩小转换”的后果。否则会在造型过程中不知不觉地丢失信息。
将一个float或double值造型成整数值后,总是将小数部分“砍掉”,不作任何进位处理。
1.14 Java没有“sizeof”
Java不需要sizeof()运算符来满足这方面的需要,因为所有数据类型在所有机器的大小都是相同的。我们不必考虑移植问题——Java本身就是一种“与平台无关”的语言。
1.15 复习计算顺序
“Ulcer Addicts Really Like C A lot”,即“溃疡患者特别喜欢(维生素)C”。
1.16 运算符总结
Tests all the operators on all the
primitive data types to show which
ones are accepted by the Java compiler.
- 如果对两个足够大的int值执行乘法运算,结果值就会溢出。
2.执行控制
2.1 真和假
所有条件语句都利用条件表达式的真或假来决定执行流程。。注意Java不允许我们将一个数字作为布尔值使用,即使它在C和C++里是允许的(真是非零,而假是零)。
2.2 if-else
2.3 循环语句
while,do-while和for控制着循环。
- 逗号运算符
了逗号运算符——注意不是逗号分隔符;后者用于分隔函数的不同自变量。Java里唯一用到逗号运算符的地方就是for循环的控制表达式。
2.4 break和continue——进一步验证
Java没有goto。然而,在break和continue这两个关键字的身上,我们仍然能看出一些goto的影子。
之所以把它们纳入goto问题中一起讨论,是由于它们使用了相同的机制:标签。
对Java来说,唯一用到标签的地方是在循环语句之前。进一步说,它实际需要紧靠在循环语句的前方——在标签和循环之间置入任何语句都是不明智的。而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另一个循环或者一个开关。这是由于break和continue关键字通常只中断当前循环,但若随同标签使用,它们就会中断到存在标签的地方。
label1:
外部循环{
内部循环{
//...
break; //1
//...
continue; //2
//...
continue label1; //3
//...
break label1; //4
}
}
在条件1中,break中断内部循环,并在外部循环结束。在条件2中,continue移回内部循环的起始处。但在条件3中,continue label1却同时中断内部循环以及外部循环,并移至label1处。随后,它实际是继续循环,但却从外部循环开始。在条件4中,break label1也会中断所有循环,并回到label1处,但并不重新进入循环。也就是说,它实际是完全中止了两个循环。