排版格式调整

This commit is contained in:
LingCoder
2019-04-13 16:47:14 +08:00
parent cbd52bb4a1
commit bd9b6b2d6c
6 changed files with 93 additions and 100 deletions

View File

@@ -8,7 +8,7 @@
Java 是从 C++ 的基础上做了一些改进和简化发展而成的。对于 C/C++ 程序员来说Java 的运算符并不陌生。如果你已了解 C 或 C++,大可以跳过本章和下一章,直接阅读 Java 与 C/C++ 不同的地方。
如果理解这两章的内容对你来说还有点困难,那么我推荐你先了解下 *Thinking in C* 再继续后面的学习。 这本书现在可以在 [www.OnJava8.com](http://www.OnJava8.com]) 上免费下载。它的内容包含音频讲座、幻灯片、练习和解决方案,专门用于帮助你快速掌握学习 Java 所需的基础知识。
如果理解这两章的内容对你来说还有点困难,那么我推荐你先了解下 Thinking in C 再继续后面的学习。 这本书现在可以在 [www.OnJava8.com](http://www.OnJava8.com]) 上免费下载。它的内容包含音频讲座、幻灯片、练习和解决方案,专门用于帮助你快速掌握学习 Java 所需的基础知识。
<!-- Using-Java-Operators -->
@@ -17,7 +17,7 @@ Java 是从 C++ 的基础上做了一些改进和简化发展而成的。对于
运算符接受一个或多个参数并生成新值。这个参数与普通方法调用的形式是不同的,但效果是相同的。加法 `+`,减法 `-`,乘法 `*`,除法 `/` 以及赋值 `=` 在任何编程语言中的工作方式都是类似的。所有运算符都能根据自己的运算对象生成一个值。除此以外,一个运算符可改变运算对象的值,这叫作“副作用”(**Side Effect**)。运算符最常见的用途就是修改自己的运算对象,从而产生副作用。但要注意生成的值亦可由没有副作用的运算符生成。
几乎所有运算符都只能操作基本类型(*Primitives*)。唯一的例外是 `=``==``!=`,它们能操作所有对象(这也是令人混淆的一个地方)。除此以外,**String** 类支持 `+``+=`
几乎所有运算符都只能操作基本类型Primitives。唯一的例外是 `=``==``!=`,它们能操作所有对象(这也是令人混淆的一个地方)。除此以外,**String** 类支持 `+``+=`
<!-- Precedence -->
@@ -98,7 +98,7 @@ public class Assignment {
这是个简单的 `Tank` 类,通过 main 方法 `new` 出了 2 个实例对象。 两个对象的 `level` 属性分别被赋予了不同的值。 然后t2 的值被赋予给 t1。在许多编程语言里预期的结果是 t1 和 t2 的值会一直相对独立。但是,在 Java 中,由于赋予的只是对象的引用,改变 t1 也就改变了 t2。 这是因为 t1 和 t2 此时指向的是堆中同一个对象。t1 原始对象的引用在 t2 赋值给其时被丢失,它就将会在垃圾回收时被清理)。
这种现象通常称为别名(*aliasing*),这是 Java 处理对象的一种基本方式。但是假若你不想这里出现这样的混淆的话,你可以这么做。代码示例:
这种现象通常称为别名aliasing这是 Java 处理对象的一种基本方式。但是假若你不想这里出现这样的混淆的话,你可以这么做。代码示例:
```java
t1.level = t2.level;
@@ -140,13 +140,13 @@ public class PassObject {
2: x.c: z
```
在许多编程语言中,方法 **f()** 似乎在内部复制其参数 **Letter y**。但是一旦传递了一个引用,那么实际上 `y.c ='z';` 是在方法 **f()** 之外改变对象。别名现象以及其解决方案是个复杂的问题,在附录中有包含:[对象传递和返回](./Appendix-Passing-and-Returning-Objects.md)。意识到这一点,我们可以警惕类似的陷阱。
在许多编程语言中,方法 `f()` 似乎在内部复制其参数 **Letter y**。但是一旦传递了一个引用,那么实际上 `y.c ='z';` 是在方法 `f()` 之外改变对象。别名现象以及其解决方案是个复杂的问题,在附录中有包含:[对象传递和返回](./Appendix-Passing-and-Returning-Objects.md)。意识到这一点,我们可以警惕类似的陷阱。
<!-- Mathematical Operators -->
## 算术运算符
Java 的基本算术运算符与其他大多编程语言是相同的。其中包括加号 `+`、减号 `-`、除号 `/`、乘号 `*` 以及模数`%`(从整数除法中获得余数)。整数除法会直接砍掉小数,而不是进位。
Java 的基本算术运算符与其他大多编程语言是相同的。其中包括加号 `+`、减号 `-`、除号 `/`、乘号 `*` 以及模数 `%`(从整数除法中获得余数)。整数除法会直接砍掉小数,而不是进位。
Java 也用一种简写形式同时进行运算和赋值操作,由运算符后跟等号表示,并且与语言中的所有运算符一致(只要有意义)。为了将 4 的值赋予给变量 x 同时将结果赋予给 x 可用 x += 4 来表示。下面带来代码更多代码示例:
@@ -230,7 +230,7 @@ u *= v : 5.2778773
u /= v : 9.940527
```
为了生成随机数字,程序首先创建一个 **Random** 对象。不带参数的 **Random** 对象会利用当前的时间用作随机数生成器的“种子”(*seed*),从而为程序的每次执行生成不同的输出。在本书的示例中,重要的是每个示例末尾的输出尽可能一致,以便可以使用外部工具进行验证。所以我们通过在创建 **Random** 对象时提供种子(随机数生成器的初始化值,其始终为特定种子值产生相同的序列),让程序每次执行都生成相同的随机数,如此以来输出结果就是可验证的 [^1]。 若需要生成随机值,可删除代码示例中的种子参数。该对象通过调用方法 **nextInt()****nextFloat()**(还可以调用 **nextLong()****nextDouble()**),使用 **Random** 对象生成许多不同类型的随机数。**nextInt()** 的参数设置生成的数字的上限下限为零为了避免零除的可能性结果偏移1。
为了生成随机数字,程序首先创建一个 **Random** 对象。不带参数的 **Random** 对象会利用当前的时间用作随机数生成器的“种子”seed从而为程序的每次执行生成不同的输出。在本书的示例中重要的是每个示例末尾的输出尽可能一致以便可以使用外部工具进行验证。所以我们通过在创建 **Random** 对象时提供种子(随机数生成器的初始化值,其始终为特定种子值产生相同的序列),让程序每次执行都生成相同的随机数,如此以来输出结果就是可验证的 [^1]。 若需要生成随机值,可删除代码示例中的种子参数。该对象通过调用方法 `nextInt()``nextFloat()`(还可以调用 `nextLong()``nextDouble()`),使用 **Random** 对象生成许多不同类型的随机数。`nextInt()` 的参数设置生成的数字的上限下限为零为了避免零除的可能性结果偏移1。
<!-- Unary Minus and Plus Operators -->
@@ -296,7 +296,7 @@ i: 1
对于前缀形式,我们将在执行递增/减操作后获取值;使用后缀形式,我们将在执行递增/减操作之前获取值。它们是唯一具有“副作用”的运算符(除那些涉及赋值的以外) —— 它们既改变操作数又改变值。
C++ 名称来自于递增运算符,同时也代表着“比 C 更进一步”。在早期的 Java 演讲中,*Bill Joy* Java 创建者之一)说“**Java = C ++ --**”C++ 减减)。这意味着 Java 是在 C++ 的基础上减少了许多不必要的东西,因此语言更简单。随着进一步地学习,我们会发现 Java 的确有许多地方相对 C++ 来说更简便,但是在其他方面,难度并不会比 C++ 小多少。
C++ 名称来自于递增运算符,同时也代表着“比 C 更进一步”。在早期的 Java 演讲中,*Bill Joy*Java 者之一)说“**Java = C ++ --**”C++ 减减)。这意味着 Java 是在 C++ 的基础上减少了许多不必要的东西,因此语言更简单。随着进一步地学习,我们会发现 Java 的确有许多地方相对 C++ 来说更简便,但是在其他方面,难度并不会比 C++ 小多少。
<!-- Relational-Operators -->
@@ -354,9 +354,9 @@ public class EqualsMethod2 {
false
```
上例的结果再次令人困惑:结果是错误的。原因: **equals()** 的默认行为是比较对象的引用而非具体内容。因此,除非你在新类中重写 **equals()** 方法,否则我们将获取不到想要的结果。不幸的是,在学习 [复用](./08-Reuse.md)**Reuse** 章节后我们才能接触到“覆盖”(**override**),并且直到 [附录:集合主题](./Appendix-Collection-Topics.md),才能知道定义 **equals()** 方法的正确方式,但是现在明白 **equals()** 行为方式也可能为你节省一些时间。
上例的结果再次令人困惑:结果是错误的。原因: `equals()` 的默认行为是比较对象的引用而非具体内容。因此,除非你在新类中重写 `equals()` 方法,否则我们将获取不到想要的结果。不幸的是,在学习 [复用](./08-Reuse.md)**Reuse** 章节后我们才能接触到“覆盖”(**Override**),并且直到 [附录:集合主题](./Appendix-Collection-Topics.md),才能知道定义 **equals()** 方法的正确方式,但是现在明白 `equals()` 行为方式也可能为你节省一些时间。
大多数 Java 库类通过覆写 **equals()** 方法比较对象的内容而不是其引用。
大多数 Java 库类通过覆写 `equals()` 方法比较对象的内容而不是其引用。
<!-- Logical-Operators -->
## 逻辑运算符
@@ -408,7 +408,7 @@ i != j is true
```
在 Java 逻辑运算中,我们不能像 C/C++ 那样使用非布尔值, 而仅能使用 **AND**、**OR**、**NOT**。
下面是一次错误的尝试: ~~a || -~~。 但是,后续表达式使用关系比较生成布尔值,然后对结果使用逻辑运算结果。请注意,如果在预期为 **String** 类型的位置使用 **boolean**类型的值,则结果会自动转为适当的文本格式。
下面是一次错误的尝试: ~~a || -~~。 但是,后续表达式使用关系比较生成布尔值,然后对结果使用逻辑运算结果。请注意,如果在预期为 **String** 类型的位置使用 **boolean** 类型的值,则结果会自动转为适当的文本格式。
我们可以将前一个程序中 **int** 的定义替换为除 **boolean** 之外的任何其他基本数据类型。
但请注意,**float** 类型的数值比较非常严格。只要最小位部分的数字不同则两个数值之间的比较仍然是“非等”的;只要数字最小位是大于 0 的,那么它就不等于 0。
@@ -417,7 +417,7 @@ i != j is true
<!-- Short-Circuiting -->
### 短路
逻辑运算符支持一种称为“短路”(*short-circuiting*)的现象。整个表达式会在运算到可以明确结果时就停止并返回结果,这意味着该逻辑表达式的后半部分不会被执行到。代码示例:
逻辑运算符支持一种称为“短路”short-circuiting的现象。整个表达式会在运算到可以明确结果时就停止并返回结果这意味着该逻辑表达式的后半部分不会被执行到。代码示例
```java
// operators / ShortCircuit.java
@@ -549,7 +549,7 @@ bll: 101111101011111010111110101111
Java 7 引入了二进制的字面值常量,由前导 `0B` 或 `0B` 表示,它可以初始化所有的整数类型。
使用整型数值类型时,显示其二进制形式会很有用。在 Long 型和 Integer 型中这很容易实现,调用其静态的 **toBinaryString()** 方法即可。 但是请注意,若将较小的类型传递给 **Integer.tobinarystring()** 时,类型将自动转换为 **int**。
使用整型数值类型时,显示其二进制形式会很有用。在 Long 型和 Integer 型中这很容易实现,调用其静态的 `toBinaryString()` 方法即可。 但是请注意,若将较小的类型传递给 **Integer.**`tobinarystring()` 时,类型将自动转换为 **int**。
<!-- Underscores in Literals -->
### 下划线
@@ -653,14 +653,14 @@ float f4 = 1e-47f; //10 的幂数
按位运算符和逻辑运算符都使用了同样的字符,只不过数量不同。“按位”短“移位”长。按位运算符可与等号 `=` 联合使用以接收结果及赋值:`&=``|=` 和 `^=` 都是合法的(由于 `~` 是一元运算符,所以不可与 `=` 联合使用)。
我们将 **Boolean** 类型被视为“单位值”(*one-bit value*)对待,所以它多少有些独特的地方。我们可以执行按位“与”、“或”、“异或”,但不能执行按位“非”(大概是为了避免与逻辑“非”混淆)。对于布尔值,按位运算符具有与逻辑运算符相同的效果,只是它们不会中途“短路”。此外,针对布尔值进行的按位运算为我们新增了一个“异或”逻辑运算符,它并未包括在“逻辑”运算符的列表中。在移位表达式中,禁止使用布尔运算,原因将在下面解释。
我们将 **Boolean** 类型被视为“单位值”one-bit value对待所以它多少有些独特的地方。我们可以执行按位“与”、“或”、“异或”但不能执行按位“非”大概是为了避免与逻辑“非”混淆。对于布尔值按位运算符具有与逻辑运算符相同的效果只是它们不会中途“短路”。此外针对布尔值进行的按位运算为我们新增了一个“异或”逻辑运算符它并未包括在“逻辑”运算符的列表中。在移位表达式中禁止使用布尔运算原因将在下面解释。
<!-- Shift Operators -->
## 移位运算符
移位运算符面向的运算对象也是二进制的“位”。可单独用它们处理整数类型(基本类型的一种)。左移位运算符 `<<` 能将其左边的运算对象向左移动右侧指定的位数(在低位补 0。右移位运算符 `>>` 则相反。位移运算符有“正”、“负”值”:若值为正,则在高位插入 0若值为负则在高位插入 1。Java 也添加了一种“不分正负”的右移位运算符(>>>),它使用了“零扩展”(*zero extension*):无论正负,都在高位插入 0。这一运算符是 C/C++ 没有的。
移位运算符面向的运算对象也是二进制的“位”。可单独用它们处理整数类型(基本类型的一种)。左移位运算符 `<<` 能将其左边的运算对象向左移动右侧指定的位数(在低位补 0。右移位运算符 `>>` 则相反。位移运算符有“正”、“负”值”:若值为正,则在高位插入 0若值为负则在高位插入 1。Java 也添加了一种“不分正负”的右移位运算符(>>>它使用了“零扩展”zero extension无论正负都在高位插入 0。这一运算符是 C/C++ 没有的。
如果移动 **char**、**byte** 或 **short**,则会在移动发生之前将其提升为 **int**,结果为 **int**。仅使用右侧的 5 个低阶位。这可以防止我们移动超过 **int** 范围的位数。若对一个 **long** 值进行处理,最后得到的结果也是 **long**。
@@ -816,7 +816,7 @@ i >>> 5, int: 97591828, binary:
```
结尾的两个方法 **printBinaryInt()****printBinaryLong()** 它们分别操作一个 **int** 和 **long** 值,并转换为二进制格式输出,同时附有简要的文字说明。除了演示 **int** 和 **long** 的所有位运算符的效果之外,本示例还显示 **int** 和 **long** 的最小值、最大值、+1 和 -1 值以便我们了解它们的形式。注意高位代表符号0 表示正1 表示负。上面显示了 **int** 部分的输出。数字的二进制表示称为有符号的两个补数。
结尾的两个方法 `printBinaryInt()``printBinaryLong()` 它们分别操作一个 **int** 和 **long** 值,并转换为二进制格式输出,同时附有简要的文字说明。除了演示 **int** 和 **long** 的所有位运算符的效果之外,本示例还显示 **int** 和 **long** 的最小值、最大值、+1 和 -1 值以便我们了解它们的形式。注意高位代表符号0 表示正1 表示负。上面显示了 **int** 部分的输出。数字的二进制表示称为有符号的两个补数。
<!-- Ternary-if-else-Operator -->
@@ -864,7 +864,7 @@ static int standardIfElse(int i) {
100
```
可以看出,**ternary()** 中的代码更简短。然而,**standardIfElse()** 中的代码更易理解且不要求更多的录入。所以我们在挑选三元运算符时,请务必权衡一下利弊。
可以看出,`ternary()` 中的代码更简短。然而,**standardIfElse()** 中的代码更易理解且不要求更多的录入。所以我们在挑选三元运算符时,请务必权衡一下利弊。
<!-- String-Operator-+-and-+= -->
@@ -1483,7 +1483,7 @@ bigger = -4
<!-- Summary -->
## 本章小结
如果你已接触过一门 C 语法风格编程语言,那么你在学习 Java 的运算符时实际上没有任何曲线。如果你觉得有难度,那么我推荐你要先去 www.OnJava8.com 观看 *Thinking in C* 的视频教程来补充一些前置知识储备。
如果你已接触过一门 C 语法风格编程语言,那么你在学习 Java 的运算符时实际上没有任何曲线。如果你觉得有难度,那么我推荐你要先去 www.OnJava8.com 观看 Thinking in C 的视频教程来补充一些前置知识储备。
[^1]: 我在 *Pomona College* 大学读过两年本科,在那里 47 被称之为“魔法数字”(*magic number*),详见 [维基百科](https://en.wikipedia.org/wiki/47_(number)) 。