Skip to content

Commit 95e07bf

Browse files
authored
Merge pull request lingcoder#78 from xiangflight/master
[modify 04](截至 第4章 结束)
2 parents 3a8e347 + 65f9777 commit 95e07bf

File tree

1 file changed

+17
-21
lines changed

1 file changed

+17
-21
lines changed

docs/book/04-Operators.md

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ float f4 = 1e-43f; //10 的幂数
681681
## 移位运算符
682682

683683

684-
移位运算符面向的运算对象也是二进制的“位”。可单独用它们处理整数类型(基本类型的一种)。左移位运算符 `<<` 能将其左边的运算对象向左移动右侧指定的位数(在低位补 0)。右移位运算符 `>>` 则相反。位移运算符有“正”、“负”值:若值为正,则在高位插入 0;若值为负,则在高位插入 1。Java 也添加了一种“不分正负”的右移位运算符(>>>),它使用了“零扩展”(zero extension):无论正负,都在高位插入 0。这一运算符是 C/C++ 没有的。
684+
移位运算符面向的运算对象也是二进制的“位”。它们只能用于处理整数类型(基本类型的一种)。左移位运算符 `<<` 能将其左边的运算对象向左移动右侧指定的位数(在低位补 0)。右移位运算符 `>>` 则相反。右移位运算符有“正”、“负”值:若值为正,则在高位插入 0;若值为负,则在高位插入 1。Java 也添加了一种“不分正负”的右移位运算符(>>>),它使用了“零扩展”(zero extension):无论正负,都在高位插入 0。这一运算符是 C/C++ 没有的。
685685

686686
如果移动 **char****byte****short**,则会在移动发生之前将其提升为 **int**,结果为 **int**。仅使用右侧的 5 个低阶位。这可以防止我们移动超过 **int** 范围的位数。若对一个 **long** 值进行处理,最后得到的结果也是 **long**
687687

@@ -837,7 +837,7 @@ i >>> 5, int: 97591828, binary:
837837
```
838838

839839

840-
结尾的两个方法 `printBinaryInt()``printBinaryLong()` 它们分别操作一个 **int****long** 值,并转换为二进制格式输出,同时附有简要的文字说明。除了演示 **int****long** 的所有位运算符的效果之外,本示例还显示 **int****long** 的最小值、最大值、+1 和 -1 值,以便我们了解它们的形式。注意高位代表符号:0 表示正,1 表示负。上面显示了 **int** 部分的输出。数字的二进制表示称为有符号的两个补数。
840+
结尾的两个方法 `printBinaryInt()``printBinaryLong()` 分别操作一个 **int****long** 值,并转换为二进制格式输出,同时附有简要的文字说明。除了演示 **int****long** 的所有位运算符的效果之外,本示例还显示 **int****long** 的最小值、最大值、+1 和 -1 值,以便我们了解它们的形式。注意高位代表符号:0 表示正,1 表示负。上面显示了 **int** 部分的输出。数字的二进制表示称为有符号的两个补数。
841841

842842

843843
<!-- Ternary-if-else-Operator -->
@@ -862,9 +862,9 @@ static int ternary(int i) {
862862

863863
static int standardIfElse(int i) {
864864
if(i < 10)
865-
return i * 100;
865+
return i * 100;
866866
else
867-
return i * 10;
867+
return i * 10;
868868
}
869869

870870
public static void main(String[] args) {
@@ -922,16 +922,16 @@ x, y, z (summed) = 3
922922
0
923923
```
924924

925-
**注意**:上例中第 1 输出语句的执行结果是 `012` 而并非 `3`,这是因为编译器将其分别转换为其字符串形式然后与字符串变量 **s** 连接。在第 2 条输出语句中,编译器将开头的变量转换为了字符串,由此可以看出,这种转换与数据的位置无无关系,只要当中有一条数据是字符串类型,其他非字符串数据都将被转换为字符串形式并连接。最后一条输出语句,我们可以看出 `+=` 运算符可以拼接其右侧的字符串连接结果并重赋值给自身变量 `s`。括号 `()` 可以控制表达式的计算顺序,以便在显示 **int** 之前对其进行实际求和。
925+
**注意**:上例中第 1 输出语句的执行结果是 `012` 而并非 `3`,这是因为编译器将其分别转换为其字符串形式然后与字符串变量 **s** 连接。在第 2 条输出语句中,编译器将开头的变量转换为了字符串,由此可以看出,这种转换与数据的位置无关,只要当中有一条数据是字符串类型,其他非字符串数据都将被转换为字符串形式并连接。最后一条输出语句,我们可以看出 `+=` 运算符可以拼接其右侧的字符串连接结果并重赋值给自身变量 `s`。括号 `()` 可以控制表达式的计算顺序,以便在显示 **int** 之前对其进行实际求和。
926926

927927
请注意主方法中的最后一个例子:我们经常会看到一个空字符串 `""` 跟着一个基本类型的数据。这样可以隐式地将其转换为字符串,以代替繁琐的显式调用方法(如这里可以使用 **Integer.toString()**)。
928928

929-
930929
<!-- Common-Pitfalls-When-Using-Operators -->
930+
931931
## 常见陷阱
932932

933933

934-
使用运算符时很容易犯的一个错误是,在还没搞清楚表达式的计算方式时就试图忽略括号 `()`。在 Java 中也一样。 在 C++ 中你甚至可能凡这样极端的错误.代码示例:
934+
使用运算符时很容易犯的一个错误是,在还没搞清楚表达式的计算方式时就试图忽略括号 `()`。在 Java 中也一样。 在 C++ 中你甚至可能犯这样极端的错误.代码示例:
935935

936936
```java
937937
while(x = y) {
@@ -970,7 +970,7 @@ public class Casting {
970970

971971
诚然,你可以这样地去转换一个数值类型的变量。但是上例这种做法是多余的:因为编译器会在必要时自动提升 **int** 型数据为 **long** 型。
972972

973-
当然,为了程序逻辑清晰或提醒自己留意,我们也可以显式地类型转换。在其他情况下,类型转换型只有在代码编译时才显出其重要性。在 C/C++ 中,类型转换有时会让人头痛。在 Java 里,类型转换则是一种比较安全的操作。但是,若将数据类型进行“向下转换”(**Narrowing Conversion**)的操作(将容量较大的数据类型转换成容量较小的类型),可能会发生信息丢失的危险。此时,编译器会强迫我们进行造型,好比在提醒我们:该操作可能危险,若你坚持让我这么做,那么对不起,请明确需要转换的类型。 对于“向上转换”(**Widening conversion**),则不必进行显式的类型转换,因为较大类型的数据肯定能容纳较小类型的数据,不会造成任何信息的丢失。
973+
当然,为了程序逻辑清晰或提醒自己留意,我们也可以显式地类型转换。在其他情况下,类型转换型只有在代码编译时才显出其重要性。在 C/C++ 中,类型转换有时会让人头痛。在 Java 里,类型转换则是一种比较安全的操作。但是,若将数据类型进行“向下转换”(**Narrowing Conversion**)的操作(将容量较大的数据类型转换成容量较小的类型),可能会发生信息丢失的危险。此时,编译器会强迫我们进行转型,好比在提醒我们:该操作可能危险,若你坚持让我这么做,那么对不起,请明确需要转换的类型。 对于“向上转换”(**Widening conversion**),则不必进行显式的类型转换,因为较大类型的数据肯定能容纳较小类型的数据,不会造成任何信息的丢失。
974974

975975
除了布尔类型的数据, Java 允许任何基本类型的数据转换为另一种基本类型的数据。此外,类是不能进行类型转换的。为了将一个类转换为另一个类型,需要使用特殊的方法(后面将会学习到如何在父子类之间进行向上/向下转型,例如,“橡树”可以转换为“树”,反之亦然。而对于“岩石”是无法转换为“树”的)。
976976

@@ -1029,28 +1029,28 @@ public class RoundingNumbers {
10291029
Math.round(above): 1
10301030
Math.round(below): 0
10311031
Math.round(fabove): 1
1032-
`Math.round(fbelow): 0
1032+
Math.round(fbelow): 0
10331033
```
10341034

1035-
自从 `round()` 方法成为了 `java.lang` 的一部分,我们就无需通过 `import` 来使用了
1035+
因为 `round()` 方法是 `java.lang` 的一部分,所以我们无需通过 `import` 就可以使用
10361036

10371037
<!-- Promotion -->
10381038
### 类型提升
10391039

10401040

1041-
你会发现,如果我们对小于 **int** 的基元数据类型(即 **char****byte****short**)执行任何算术或按位操作,这些值会在执行操作之前类型提升为 **int**,并且结果值的类型为 **int**若想重新使用到较小的类型,必须使用强制转换(由于重新分配回一个较小的类型,结果可能会丢失精度)。通常,表达式中最大的数据类型是决定表达式结果的数据类型。**float** 型和 **double** 型相乘,结果是 **double** 型的;**int****long** 相加,结果是 **long** 型。
1041+
你会发现,如果我们对小于 **int** 的基本数据类型(即 **char****byte****short**)执行任何算术或按位操作,这些值会在执行操作之前类型提升为 **int**,并且结果值的类型为 **int**若想重新使用较小的类型,必须使用强制转换(由于重新分配回一个较小的类型,结果可能会丢失精度)。通常,表达式中最大的数据类型是决定表达式结果的数据类型。**float** 型和 **double** 型相乘,结果是 **double** 型的;**int****long** 相加,结果是 **long** 型。
10421042

10431043

10441044
<!-- Java-Has-No-sizeof -->
10451045
## Java没有sizeof
10461046

10471047

1048-
在 C/C++ 中,经常 需要用到 `sizeof()` 方法来获取数据被分配的字符大小。在 C/C++ 中,`sizeof() `最常见的应用就是“移植”。不同数据在不同机器上可能有不同的大小,所以在进行大小敏感的运算时,程序员必须对这些类型有多大做到心中有数。例如,一台计算机可用 32 位来保存整数,而另一台只用 16 位保存。显然,在第一台机器中,程序可保存更大的值。所以,移植是令 C/C++ 程序员颇为头痛的一个问题。
1049-
1050-
Java 不需要` sizeof()` 方法来满足这种需求,因为所有类型的默认大小在不同平台间是相同的。我们不必考虑这个层次的移植问题 —— Java 本身就是一种“与平台无关”的语言。
1048+
在 C/C++ 中,经常需要用到 `sizeof()` 方法来获取数据项被分配的字节大小。C/C++ 中使用 `sizeof()` 最有说服力的原因是为了移植性,不同数据在不同机器上可能有不同的大小,所以在进行大小敏感的运算时,程序员必须对这些类型有多大做到心中有数。例如,一台计算机可用 32 位来保存整数,而另一台只用 16 位保存。显然,在第一台机器中,程序可保存更大的值。所以,移植是令 C/C++ 程序员颇为头痛的一个问题。
10511049

1050+
Java 不需要 ` sizeof()` 方法来满足这种需求,因为所有类型的大小在不同平台上是相同的。我们不必考虑这个层次的移植问题 —— Java 本身就是一种“与平台无关”的语言。
10521051

10531052
<!-- A-Compendium-of-Operators -->
1053+
10541054
## 运算符总结
10551055

10561056
上述示例分别向我们展示了哪些基本类型能被用于特定的运算符。基本上,下面的代码示例是对上述所有示例的重复,只不过概括了所有的基本类型。这个文件能被正确地编译,因为我已经把编译不通过的那部分用注释 `//` 过滤了。代码示例:
@@ -1474,7 +1474,7 @@ public class AllOps {
14741474

14751475
**注意****boolean** 类型的的运算是受限的。你能为其赋值 `true``false`,也可测试它的值是否是 `true``false`。但你不能对其作加减等其他运算。
14761476

1477-
**char** , **byte****short** 类型中,我们可以看到算术运算符的“类型转换”效果。我们必须要显式强制类型转换才能将结果重新赋值为原始类型。对于 **int** 类型的运算则不用转换,因为默认就是 **int** 型。虽然我们不用再停下来思考这一切是否安全,但是两个大的 int 型相乘时,结果有可能超出 **int** 型的范围,这种情况下结果会发生溢出。下面的代码示例:
1477+
**char** , **byte****short** 类型中,我们可以看到算术运算符的“类型转换”效果。我们必须要显式强制类型转换才能将结果重新赋值为原始类型。对于 **int** 类型的运算则不用转换,因为默认就是 **int** 型。虽然我们不用再停下来思考这一切是否安全,但是两个大的 int 型整数相乘时,结果有可能超出 **int** 型的范围,这种情况下结果会发生溢出。下面的代码示例:
14781478

14791479
```java
14801480
// operators/Overflow.java
@@ -1498,7 +1498,7 @@ bigger = -4
14981498

14991499
编译器没有报错或警告,运行时一切看起来都无异常。诚然,Java 是优秀的,但是还不足够优秀。
15001500

1501-
对于 **char****byte** 或者 **short**,混合赋值并不需要类型转换。即使为它们执行转型操作,也会获得与直接算术运算相同的结果。另外,省略类型转换可以使代码显得更加简练。总之,除 **boolean** 以外,其他任何两种基本类型间都可进行类型转换。当我们进行向下转换类型时,需要注意结果的范围是否溢出,否则我们就很可能在不知不觉种丢失精度
1501+
对于 **char****byte** 或者 **short**,混合赋值并不需要类型转换。即使为它们执行转型操作,也会获得与直接算术运算相同的结果。另外,省略类型转换可以使代码显得更加简练。总之,除 **boolean** 以外,其他任何两种基本类型间都可进行类型转换。当我们进行向下转换类型时,需要注意结果的范围是否溢出,否则我们就很可能在不知不觉中丢失精度
15021502

15031503

15041504
<!-- Summary -->
@@ -1508,11 +1508,7 @@ bigger = -4
15081508

15091509
[^1]: 我在 *Pomona College* 大学读过两年本科,在那里 47 被称之为“魔法数字”(*magic number*),详见 [维基百科](https://en.wikipedia.org/wiki/47_(number))
15101510

1511-
1512-
1513-
[^2]: *John Kirkham* 说过, “自 1960 年我开始在 IBM 1620 上开始编程起,至 1970 年之间,FORTRAN 一直都是一种全大写的编程语言。这可能是因为许多早期的输入设备都是旧的电传打字机,使用了5 位波特码,没有小写字母的功能。
1514-
1515-
指数符号中的 e 也总是大写的,并且从未与自然对数底数 e 混淆,自然对数底数 e 总是小写的。 e 简单地代表指数,通常 10 是基数。那时,八进制也被程序员广泛使用。虽然我从未见过它的用法,但如果我看到一个指数符号的八进制数,我会认为它是以 8 为基数的。我记得第一次看到指数使用小写字母 e 是在 20 世纪 70 年代末,我也发现它令人困惑。这个问题出现的时候,小写字母悄悄进入了 Fortran。如果你真的想使用自然对数底,我们实际上有一些函数要使用,但是它们都是大写的。
1511+
[^2]: *John Kirkham* 说过, “自 1960 年我开始在 IBM 1620 上开始编程起,至 1970 年之间,FORTRAN 一直都是一种全大写的编程语言。这可能是因为许多早期的输入设备都是旧的电传打字机,使用了5 位波特码,没有小写字母的功能。指数符号中的 e 也总是大写的,并且从未与自然对数底数 e 混淆,自然对数底数 e 总是小写的。 e 简单地代表指数,通常 10 是基数。那时,八进制也被程序员广泛使用。虽然我从未见过它的用法,但如果我看到一个指数符号的八进制数,我会认为它是以 8 为基数的。我记得第一次看到指数使用小写字母 e 是在 20 世纪 70 年代末,我也发现它令人困惑。这个问题出现的时候,小写字母悄悄进入了 Fortran。如果你真的想使用自然对数底,我们实际上有一些函数要使用,但是它们都是大写的。
15161512

15171513

15181514
<!-- 分页 -->

0 commit comments

Comments
 (0)