Skip to content

Commit 747affc

Browse files
committed
[modify 04](截至 第4章 指数计数法)
1 parent 2b787a0 commit 747affc

File tree

1 file changed

+42
-21
lines changed

1 file changed

+42
-21
lines changed

docs/book/04-Operators.md

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ x = a * (-b);
263263

264264
和 C 语言类似,Java 提供了许多快捷运算方式。快捷运算可使代码可读性,可写性都更强。其中包括递增 `++` 和递减 `--`,意为“增加或减少一个单位”。举个例子来说,假设 a 是一个 **int** 类型的值,则表达式 `++a` 就等价于 `a = a + 1`。 递增和递减运算符不仅可以修改变量,还可以生成变量的值。
265265

266-
每种类型的运算符,都有两个版本可供选用;通常将其称为“前缀版”和“后缀版”。“前递增”表示 `++` 运算符位于变量或表达式的前面;而“后递增”表示 `++` 运算符位于变量或表达式的后面。类似地,“前递减”意味着 `--` 运算符位于变量或表达式的前面;而“后递减”意味着 `--` 运算符位于变量或表达式的后面。对于前递增和前递减(如 `++a``--a`),会先执行递增/减运算,再返回值。而对于后递增和后递减(如 `a++``a--`),会先返回值,再执行递增/减运算。代码示例:
266+
每种类型的运算符,都有两个版本可供选用;通常将其称为“前缀”和“后缀”。“前递增”表示 `++` 运算符位于变量或表达式的前面;而“后递增”表示 `++` 运算符位于变量的后面。类似地,“前递减”意味着 `--` 运算符位于变量的前面;而“后递减”意味着 `--` 运算符位于变量的后面。对于前递增和前递减(如 `++a``--a`),会先执行递增/减运算,再返回值。而对于后递增和后递减(如 `a++``a--`),会先返回值,再执行递增/减运算。代码示例:
267267

268268
```java
269269
// operators/AutoInc.java
@@ -294,21 +294,22 @@ i--: 2
294294
i: 1
295295
```
296296

297-
对于前缀形式,我们将在执行递增/减操作后获取值;使用后缀形式,我们将在执行递增/减操作之前获取值。它们是唯一具有“副作用”的运算符(除那些涉及赋值的以外) —— 它们既改变操作数又改变值
297+
对于前缀形式,我们将在执行递增/减操作后获取值;使用后缀形式,我们将在执行递增/减操作之前获取值。它们是唯一具有“副作用”的运算符(除那些涉及赋值的以外) —— 它们修改了操作数的值
298298

299-
C++ 名称来自于递增运算符,同时也代表着“比 C 更进一步”。在早期的 Java 演讲中,*Bill Joy*(Java 作者之一)说“**Java = C ++ --**”(C++ 减减)。这意味着 Java 是在 C++ 的基础上减少了许多不必要的东西,因此语言更简单。随着进一步地学习,我们会发现 Java 的确有许多地方相对 C++ 来说更简便,但是在其他方面,难度并不会比 C++ 小多少。
299+
C++ 名称来自于递增运算符,暗示着“比 C 更进一步”。在早期的 Java 演讲中,*Bill Joy*(Java 作者之一)说“**Java = C++ --**”(C++ 减减),意味着 Java C++ 的基础上减少了许多不必要的东西,因此语言更简单。随着进一步地学习,我们会发现 Java 的确有许多地方相对 C++ 来说更简便,但是在其他方面,难度并不会比 C++ 小多少。
300300

301301

302302
<!-- Relational-Operators -->
303303
## 关系运算符
304304

305305

306-
关系运算符会通过产生一个布尔(**boolean**结果来表示被操作的数值之间的关系。如果关系为真,则结果为 **true**如果关系非真,则结果为 **false**。关系运算符包括小于 `<`,大于 `>`,小于或等于 `<=`,大于或等于 `>=`等价 `==` 和不等价 `!=``==``!=` 可与所有基本类型搭配使用。但与其他类型的比较就不太适合了,因为布尔值只能表示 **true****false**,所以比较它们之间的“大于”或“小于”没有意义。
306+
关系运算符会通过产生一个布尔(**boolean**结果来表示操作数之间的关系。如果关系为真,则结果为 **true**如果关系为假,则结果为 **false**。关系运算符包括小于 `<`,大于 `>`,小于或等于 `<=`,大于或等于 `>=`等于 `==` 和不等于 `!=``==``!=` 可用于所有基本类型,但其他运算符不能用于基本类型 **boolean**,因为布尔值只能表示 **true****false**,所以比较它们之间的“大于”或“小于”没有意义。
307307

308308
<!-- Testing Object Equivalence -->
309+
309310
### 测试对象等价
310311

311-
关系运算符 `==``!=` 同样适用于所有对象之间的比较运算,但产生的结果却经常混淆 Java 的初学者。下面是代码示例:
312+
关系运算符 `==``!=` 同样适用于所有对象之间的比较运算,但它们比较的内容却经常困扰 Java 的初学者。下面是代码示例:
312313

313314
```java
314315
// operators/Equivalence.java
@@ -329,13 +330,34 @@ true
329330
false
330331
```
331332

333+
表达式 `System.out.println(n1 == n2)` 将会输出比较的结果。因为两个 **Integer** 对象相同,所以先输出 **true**,再输出 **false**。但是,尽管对象的内容一样,对象的引用却不一样。`==``!=` 比较的是对象引用,所以输出实际上应该是先输出 **false**,再输出 **true**(译者注:如果你把47改成128,那么打印的结果就是这样,因为 Integer 内部维护着一个 IntegerCache 的缓存,默认缓存范围是 [-128, 127],所以 [-128, 127] 之间的值用 `==``!=` 比较也能能到正确的结果,但是不推荐用关系运算符比较,具体见 JDK 中的 Integer 类源码)。
334+
335+
那么怎么比较两个对象的内容是否相同呢?你必须使用所有对象(不包括基本类型)中都存在的 `equals()` 方法,下面是如何使用 `equals()` 方法的示例:
336+
337+
```java
338+
// operators/EqualsMethod.java
339+
public class EqualsMethod {
340+
public static void main(String[] args) {
341+
Integer n1 = 47;
342+
Integer n2 = 47;
343+
System.out.println(n1.equals(n2));
344+
}
345+
}
346+
```
347+
348+
输出结果:
349+
350+
```java
351+
true
352+
```
353+
332354
上例的结果看起来是我们所期望的。但其实事情并非那么简单。下面我们来创建自己的类:
333355

334356
```java
335357
// operators/EqualsMethod2.java
336358
// 默认的 equals() 方法没有比较内容
337359
class Value {
338-
int i;
360+
int i;
339361
}
340362

341363
public class EqualsMethod2 {
@@ -350,15 +372,16 @@ public class EqualsMethod2 {
350372

351373
输出结果:
352374

353-
```
375+
```java
354376
false
355377
```
356378

357-
上例的结果再次令人困惑:结果是错误的。原因: `equals()` 的默认行为是比较对象的引用而非具体内容。因此,除非你在新类中重写 `equals()` 方法,否则我们将获取不到想要的结果。不幸的是,在学习 [复用](./08-Reuse.md)**Reuse**) 章节后我们才能接触到“覆盖”(**Override**),并且直到 [附录:集合主题](./Appendix-Collection-Topics.md),才能知道定义 **equals()** 方法的正确方式,但是现在明白 `equals()` 行为方式也可能为你节省一些时间。
379+
上例的结果再次令人困惑:结果是 **false**。原因: `equals()` 的默认行为是比较对象的引用而非具体内容。因此,除非你在新类中覆写 `equals()` 方法,否则我们将获取不到想要的结果。不幸的是,在学习 [复用](./08-Reuse.md)**Reuse**) 章节后我们才能接触到“覆写”(**Override**),并且直到 [附录:集合主题](./Appendix-Collection-Topics.md),才能知道定义 `equals()` 方法的正确方式但是现在明白 `equals()` 行为方式也可能为你节省一些时间。
358380

359381
大多数 Java 库类通过覆写 `equals()` 方法比较对象的内容而不是其引用。
360382

361-
<!-- Logical-Operators -->
383+
<!-- Logical Operators -->
384+
362385
## 逻辑运算符
363386

364387
每个逻辑运算符 `&&`**AND**)、`||`**OR**)和 `!`****)根据参数的逻辑关系生成布尔值 `true``false`。下面的代码示例使用了关系运算符和逻辑运算符:
@@ -407,14 +430,12 @@ i != j is true
407430
(i < 10) || (j < 10) is false
408431
```
409432

410-
在 Java 逻辑运算中,我们不能像 C/C++ 那样使用非布尔值, 而仅能使用 **AND****OR****NOT**
411-
下面是一次错误的尝试: ~~a || -~~。 但是,后续表达式使用关系比较生成布尔值,然后对结果使用逻辑运算结果。请注意,如果在预期为 **String** 类型的位置使用 **boolean** 类型的值,则结果会自动转为适当的文本格式。
412-
413-
我们可以将前一个程序中 **int** 的定义替换为除 **boolean** 之外的任何其他基本数据类型。
414-
但请注意,**float** 类型的数值比较非常严格。只要最小位部分的数字不同则两个数值之间的比较仍然是“非等”的;只要数字最小位是大于 0 的,那么它就不等于 0。
433+
在 Java 逻辑运算中,我们不能像 C/C++ 那样使用非布尔值, 而仅能使用 **AND****OR****NOT**。上面的例子中,我们将使用非布尔值的表达式注释掉了(你可以看到表达式前面是 //-)。但是,后续的表达式使用关系比较生成布尔值,然后对结果使用了逻辑运算。请注意,如果在预期为 **String** 类型的位置使用 **boolean** 类型的值,则结果会自动转为适当的文本格式(即 "true" 或 "false" 字符串)。
415434

435+
我们可以将前一个程序中 **int** 的定义替换为除 **boolean** 之外的任何其他基本数据类型。但请注意,**float** 类型的数值比较非常严格,只要两个数字的最小位不同则两个数仍然不相等;只要数字最小位是大于 0 的,那么它就不等于 0。
416436

417437
<!-- Short-Circuiting -->
438+
418439
### 短路
419440

420441
逻辑运算符支持一种称为“短路”(short-circuiting)的现象。整个表达式会在运算到可以明确结果时就停止并返回结果,这意味着该逻辑表达式的后半部分不会被执行到。代码示例:
@@ -469,8 +490,8 @@ test1(0)&& test2(2)&& test3(2)
469490

470491
所以,运用“短路”可以节省部分不必要的运算,从而提高程序潜在的性能。
471492

472-
473493
<!-- Literals -->
494+
474495
## 字面值常量
475496

476497

@@ -540,22 +561,23 @@ bli: 101111101011111010111110101111
540561
bll: 101111101011111010111110101111
541562
```
542563

543-
在文本值的后面添加字面值常量可以让编译器识别该文本值的类型。对于 **Long** 型数值,结尾使用大写 `L` 或小写 `l` 皆可(不推荐使用 `l`,因为容易与阿拉伯数值 1 混淆)。大写 `F` 或小写 `f` 表示 **float** 浮点数。大写 `D` 或小写 `d` 表示 **double** 双精度。
564+
在文本值的后面添加字符可以让编译器识别该文本值的类型。对于 **Long** 型数值,结尾使用大写 `L` 或小写 `l` 皆可(不推荐使用 `l`,因为容易与阿拉伯数值 1 混淆)。大写 `F` 或小写 `f` 表示 **float** 浮点数。大写 `D` 或小写 `d` 表示 **double** 双精度。
544565

545566

546-
十六进制(以 16 为基数),适用于所有整型数据类型,由前导 `0x``0x` 表示,后跟 0-9 或 a-f (大写或小写)。如果我们在初始化某个类型的数值时,赋值超出其范围,那么编译器会报错(不管值的数字形式如何)。在上例的代码中,**char****byte****short** 的值已经是最大了。如果超过这些值,编译器将自动转型为 **int**并且我们需要声明强制转换(强制转换将在本章后面定义)。这告诉我们已越过该类型的范围界限
567+
十六进制(以 16 为基数),适用于所有整型数据类型,由前导 `0x``0X` 表示,后跟 0-9 或 a-f (大写或小写)。如果我们在初始化某个类型的数值时,赋值超出其范围,那么编译器会报错(不管值的数字形式如何)。在上例的代码中,**char****byte****short** 的值已经是最大了。如果超过这些值,编译器将自动转型为 **int**并且提示我们需要声明强制转换(强制转换将在本章后面定义),意味着我们已越过该类型的范围界限
547568

548569
八进制(以 8 为基数)由 0~7 之间的数字和前导零 `0` 表示。
549570

550-
Java 7 引入了二进制的字面值常量,由前导 `0B``0B` 表示,它可以初始化所有的整数类型。
571+
Java 7 引入了二进制的字面值常量,由前导 `0b``0B` 表示,它可以初始化所有的整数类型。
551572

552573
使用整型数值类型时,显示其二进制形式会很有用。在 Long 型和 Integer 型中这很容易实现,调用其静态的 `toBinaryString()` 方法即可。 但是请注意,若将较小的类型传递给 **Integer.**`tobinarystring()` 时,类型将自动转换为 **int**
553574

554575
<!-- Underscores in Literals -->
576+
555577
### 下划线
556578

557579

558-
Java 7 中有一个深思熟虑的补充:我们可以在数字文字中包含下划线 `_`,以使结果更清晰。这对于大数值的分组数字特别有用。代码示例:
580+
Java 7 中有一个深思熟虑的补充:我们可以在数字字面量中包含下划线 `_`,以使结果更清晰。这对于大数值的分组特别有用。代码示例:
559581

560582

561583
```java
@@ -590,8 +612,7 @@ public class Underscores {
590612
3. `F``D``L`的前后禁止出现 `_`
591613
4. 二进制前导 `b` 和 十六进制 `x` 前后禁止出现 `_`
592614

593-
594-
[1] 注意 `%n`的使用。熟悉 C 风格的程序员可能习惯于看到 `\n` 来表示换行符。问题在于它给你的是一个“Unix风格”的换行符。此外,如果我们使用的是 Windows,则必须指定 `\r\n`。这种差异的包袱应该由编程语言来解决。这就是Java用 `%n` 实现的,忽略平台间差异生成适当的换行符。但当你使用 `System.out.printf()``System.out.format()` 时。对于 `System.out.println()`,我们仍然必须使用 `\n`;如果你使用 `%n``println()` 只会输出 `%n` 而不是换行符。
615+
[1] 注意 `%n`的使用。熟悉 C 风格的程序员可能习惯于看到 `\n` 来表示换行符。问题在于它给你的是一个“Unix风格”的换行符。此外,如果我们使用的是 Windows,则必须指定 `\r\n`。这种差异的包袱应该由编程语言来解决。这就是Java用 `%n` 实现的可以忽略平台间差异而生成适当的换行符,但只有当你使用 `System.out.printf()``System.out.format()` 时。对于 `System.out.println()`,我们仍然必须使用 `\n`;如果你使用 `%n``println()` 只会输出 `%n` 而不是换行符。
595616

596617

597618
<!-- Exponential Notation -->

0 commit comments

Comments
 (0)