在 Java 中,运算符是对字面量、变量等操作数进行计算、比较或赋值的符号。例如,+ 可以用于数值相加,> 可以比较两个数的大小。
运算符与操作数按照 Java 的语法规则组合起来,就构成了表达式。例如:
int a = 10;:定义变量a。int b = 20;:定义变量b。int c = a + b;:计算表达式a + b,再将结果赋值给c。
其中,+ 是运算符,a + b 是表达式,= 则将计算结果赋给变量。
算术运算符的基本用法
| 运算符 | 作用 |
|---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ | 除法 |
% | 取余 |
下面直接用代码看看这些运算符的结果:
public class Test1 {
public static void main(String[] args) {
System.out.println("3+2的结果:" + (3 + 2));
System.out.println("5-1的结果:" + (5 - 1));
System.out.println("7*5的结果:" + (7 * 5));
// 如果在计算中有小数参与,结果有可能不准
System.out.println("0.1+0.2的结果:" + (0.1 + 0.2));// 0.30000000000000004
// 整数参与运算,结果还是整数,会直接丢掉小数点后的值。
System.out.println("10/3的结果:" + (10 / 3));
// 有浮点数参与计算,结果就为浮点数
System.out.println("10.0/3的结果:" + (10.0 / 3));
System.out.println("10%3的结果:" + (10 % 3));
}
}运行后,终端中可以看到以下输出(节选):
7*5的结果:35
0.1+0.2的结果:0.30000000000000004
10/3的结果:3
10.0/3的结果:3.3333333333333335
10%3的结果:1从运行结果中,可以看到浮点数计算、整数除法和取余运算的几个特点:
1. 小数参与计算时,结果有可能不太准确。 比如 0.1 + 0.2,我们平时算出来是 0.3,程序却输出了 0.30000000000000004。这与浮点数在计算机中的存储方式有关:有些十进制小数无法用有限的二进制位精确表示。这里先知道会出现精度误差就行,后续用到浮点数时再深入了解。
2. 整数除法会截去小数部分。 10 / 3 的两个操作数都是整数,结果就是 3;而 10.0 / 3 中有 double 类型的操作数,因此得到浮点数 3.3333333333333335。想保留除法的小数部分,可以让至少一个操作数使用浮点类型。
3. % 用来取余数。 这个概念其实我们小学就接触过,只是在日常算术里不一定经常用到。放到程序里,它很适合判断整除和奇偶性:10 % 2 == 0,说明 10 能被 2 整除,是偶数;11 % 2 == 1,说明 11 是奇数。
隐式转换与强制转换
隐式转换(自动类型提升)
不同数值类型参与运算时,Java 会按照运算规则进行类型提升。例如,int 和 double 相加,会先把 int 转换为 double,再进行计算,因此结果也是 double。
public class Test1 {
public static void main(String[] args) {
int a = 10;
double b = 10.33;
System.out.println(a+b);
}
}对于基本数值类型的算术运算,可以先记住两条规则:
- 不同类型的数值参与运算时,会按类型提升规则确定计算使用的类型。例如
int与double运算,结果是double。 byte、short、char参与算术运算时,至少会提升为int。所以两个byte相加,得到的也是int,不会自动变回byte。
对于这些常见数值类型,可以按下面的顺序理解提升方向:
byte / short / char → int → long → float → double
这条顺序描述的是常见数值运算的类型提升过程。char 是无符号类型,short 是有符号类型;整数转换为浮点数时也可能损失精度,因此它并不是严格按照取值范围大小排列的。
强制转换
如果需要明确将一个数值转换成另一种类型,可以使用强制类型转换。尤其是把较大范围类型的变量值赋给较小范围类型的变量时,通常需要显式写出目标类型:
目标类型 变量名 = (目标类型) 表达式;
例如,两个 byte 相加后得到的是 int,因此要把结果赋给 byte 变量,需要对相加的结果进行转换。
public class Test1 {
public static void main(String[] args) {
byte b1 = 10;
byte b2 = 20;
byte b3 = (byte) (b1 + b2);
System.out.println(b3);
}
}(byte) (b1 + b2) 先计算 b1 + b2,再把计算结果转换为 byte。
如果只写 (byte) b1 + (byte) b2,那么两个操作数虽然分别经过了强制转换,但在相加时仍会提升为 int,不能直接将这个表达式赋给 byte 变量。
强制转换可能丢失数据。例如数值超出了目标类型的表示范围,转换后的结果可能与原值不同,所以要留意目标类型的范围。
字符串的 + 操作
+ 不仅能进行数值加法,还能连接字符串。当 + 的任一操作数是字符串时,它会执行字符串拼接。例如,"123" + 123 的结果是字符串 "123123"。
连续使用 + 时,运算会按照表达式的结合顺序进行:
2020 + 6 + "你好":先计算2020 + 6,再与字符串拼接,结果是"2026你好"。"你好" + 2020 + 6:先与2020拼接,再与6拼接,结果是"你好20206"。
代码中也可以直接观察这两种情况:
public class Test1 {
public static void main(String[] args) {
System.out.println("abc" + 123);
System.out.println(2020 + 6 + "你好");
}
}终端输出:
abc123
2026你好字符相加
在 Java 中,char 表示一个 UTF-16 代码单元。对于 ASCII 范围内的字符,其数值与 ASCII 编码相同,例如小写字母 'a' 对应十进制的 97。
当字符参与数值加法时,会先进行数值类型提升。因此,'a' + 0 的结果是整数 97;但当字符与字符串拼接时,'a' + "bc" 得到的是字符串 "abc"。
public class Test1 {
public static void main(String[] args) {
System.out.println('a' + 0);//97
System.out.println('a'+"bc");//abc
}
}因此,看到 + 时,需要结合操作数的类型判断它是数值加法还是字符串拼接。
常用 ASCII 编码与速查表
ASCII 使用 7 位二进制编码,共有 0~127 这 128 个编码值,包括英文字母、数字、符号和控制字符。写 Java 代码时,下面几个字符的编码比较常用:
| 字符 | 十进制 | 十六进制 |
|---|---|---|
'0' | 48 | 30 |
'A' | 65 | 41 |
'a' | 97 | 61 |
其他字符可以在下面的完整码表中查找。
查看完整 ASCII 码表(0~127)
按十进制编码排序;展开后可在表格内滚动查看全部 128 个字符。
| 十进制 | 十六进制 | 字符 / 说明 |
|---|---|---|
| 0 | 00 | NUL(空字符) |
| 1 | 01 | SOH(标题开始) |
| 2 | 02 | STX(正文开始) |
| 3 | 03 | ETX(正文结束) |
| 4 | 04 | EOT(传输结束) |
| 5 | 05 | ENQ(询问) |
| 6 | 06 | ACK(确认) |
| 7 | 07 | BEL(响铃) |
| 8 | 08 | BS(退格) |
| 9 | 09 | HT(水平制表) |
| 10 | 0A | LF(换行) |
| 11 | 0B | VT(垂直制表) |
| 12 | 0C | FF(换页) |
| 13 | 0D | CR(回车) |
| 14 | 0E | SO(移出) |
| 15 | 0F | SI(移入) |
| 16 | 10 | DLE(数据链路转义) |
| 17 | 11 | DC1(设备控制 1) |
| 18 | 12 | DC2(设备控制 2) |
| 19 | 13 | DC3(设备控制 3) |
| 20 | 14 | DC4(设备控制 4) |
| 21 | 15 | NAK(否认) |
| 22 | 16 | SYN(同步空闲) |
| 23 | 17 | ETB(传输块结束) |
| 24 | 18 | CAN(取消) |
| 25 | 19 | EM(介质结束) |
| 26 | 1A | SUB(替换) |
| 27 | 1B | ESC(转义) |
| 28 | 1C | FS(文件分隔符) |
| 29 | 1D | GS(组分隔符) |
| 30 | 1E | RS(记录分隔符) |
| 31 | 1F | US(单元分隔符) |
| 32 | 20 | SPACE(空格) |
| 33 | 21 | ! |
| 34 | 22 | " |
| 35 | 23 | # |
| 36 | 24 | $ |
| 37 | 25 | % |
| 38 | 26 | & |
| 39 | 27 | ' |
| 40 | 28 | ( |
| 41 | 29 | ) |
| 42 | 2A | * |
| 43 | 2B | + |
| 44 | 2C | , |
| 45 | 2D | - |
| 46 | 2E | . |
| 47 | 2F | / |
| 48 | 30 | 0 |
| 49 | 31 | 1 |
| 50 | 32 | 2 |
| 51 | 33 | 3 |
| 52 | 34 | 4 |
| 53 | 35 | 5 |
| 54 | 36 | 6 |
| 55 | 37 | 7 |
| 56 | 38 | 8 |
| 57 | 39 | 9 |
| 58 | 3A | : |
| 59 | 3B | ; |
| 60 | 3C | < |
| 61 | 3D | = |
| 62 | 3E | > |
| 63 | 3F | ? |
| 64 | 40 | @ |
| 65 | 41 | A |
| 66 | 42 | B |
| 67 | 43 | C |
| 68 | 44 | D |
| 69 | 45 | E |
| 70 | 46 | F |
| 71 | 47 | G |
| 72 | 48 | H |
| 73 | 49 | I |
| 74 | 4A | J |
| 75 | 4B | K |
| 76 | 4C | L |
| 77 | 4D | M |
| 78 | 4E | N |
| 79 | 4F | O |
| 80 | 50 | P |
| 81 | 51 | Q |
| 82 | 52 | R |
| 83 | 53 | S |
| 84 | 54 | T |
| 85 | 55 | U |
| 86 | 56 | V |
| 87 | 57 | W |
| 88 | 58 | X |
| 89 | 59 | Y |
| 90 | 5A | Z |
| 91 | 5B | [ |
| 92 | 5C | \ |
| 93 | 5D | ] |
| 94 | 5E | ^ |
| 95 | 5F | _ |
| 96 | 60 | ` |
| 97 | 61 | a |
| 98 | 62 | b |
| 99 | 63 | c |
| 100 | 64 | d |
| 101 | 65 | e |
| 102 | 66 | f |
| 103 | 67 | g |
| 104 | 68 | h |
| 105 | 69 | i |
| 106 | 6A | j |
| 107 | 6B | k |
| 108 | 6C | l |
| 109 | 6D | m |
| 110 | 6E | n |
| 111 | 6F | o |
| 112 | 70 | p |
| 113 | 71 | q |
| 114 | 72 | r |
| 115 | 73 | s |
| 116 | 74 | t |
| 117 | 75 | u |
| 118 | 76 | v |
| 119 | 77 | w |
| 120 | 78 | x |
| 121 | 79 | y |
| 122 | 7A | z |
| 123 | 7B | { |
| 124 | 7C | | |
| 125 | 7D | } |
| 126 | 7E | ~ |
| 127 | 7F | DEL(删除) |
自增与自减运算符
| 运算符 | 作用 |
|---|---|
++ | 使变量的值增加 1 |
-- | 使变量的值减少 1 |
++ 和 -- 都有前置和后置两种写法。单独执行 a++ 或 ++a,都会让 a 增加 1;自减同理。
下面的代码先执行 a++,再执行 ++a,因此 a 从 10 变为 12。
public class Test1 {
public static void main(String[] args) {
int a = 10;
a++;
++a;
System.out.println(a);
}
}不过一旦要参与其他计算,就需要区分前置和后置了。可以先记一个很直观的说法:a++ 是“先用后加”,++a 是“先加后用”。 这是什么意思?我们直接看下面的例子。
a++:表达式先使用a原来的值,再将a加1。++a:先将a加1,表达式再使用更新后的值。
public class Test1 {
public static void main(String[] args) {
int a = 10;
int b = a++ + 1;
System.out.println(b);//11
// 重置a为10,避免上面的运算影响下面的结果
a = 10;
int c = 1 + ++a;//12
System.out.println(c);
}
}第一句 int b = a++ + 1; 是先用后加:先拿 a 原来的值 10 去计算 10 + 1,所以 b 得到 11;然后 a 自己再加 1,变成 11。
为了不让上一句影响第二个例子,我们把 a 重新设为 10。接下来 int c = 1 + ++a; 是先加后用:a 先变为 11,再参与 1 + 11,因此 c 得到 12。这样对比起来,就比较容易看出两种写法的区别了。
赋值运算符
| 运算符 | 作用 | 示例 |
|---|---|---|
= | 直接赋值 | a = 10 |
+= | 相加后赋值 | a += b |
-= | 相减后赋值 | a -= b |
*= | 相乘后赋值 | a *= b |
/= | 相除后赋值 | a /= b |
%= | 取余后赋值 | a %= b |
以 += 为例,a += b 表示把 a + b 的结果重新赋给 a。其他复合赋值运算符也遵循类似规则。
public class Test1 {
public static void main(String[] args) {
int a = 10;
int b = 20;
b += a;
System.out.println(b);//30
b -= a;
System.out.println(b);//20
b *= a;
System.out.println(b);//200
}
}这段代码先让 b 从 20 增加到 30,随后减去 a 变回 20,最后乘以 a 得到 200。三次输出依次是 30、20、200。
复合赋值还有一个类型转换细节:两个 byte 相加时,表达式结果是 int。但写成 b1 += b2,Java 会隐式地将结果转换回 byte;如果写成 b1 = b1 + b2,则会因为类型不匹配而无法编译。这里的隐式转换也可能造成数据丢失。
关系运算符
关系运算符可以比较数值大小或判断两个值是否相等。下面以基本类型的数值比较为例:
| 运算符 | 含义 | 示例 |
|---|---|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
> | 大于 | a > b |
>= | 大于等于 | a >= b |
< | 小于 | a < b |
<= | 小于等于 | a <= b |
比较表达式的结果是 boolean 类型,即 true 或 false。其中 == 用于比较,= 用于赋值,二者的含义不同。
public class Test1 {
public static void main(String[] args) {
System.out.println(1 == 1);// true
System.out.println(1 != 1);//false
System.out.println(2 > 3);//false
System.out.println(2 < 3);//true
System.out.println(3<=3);//true
}
}对于引用类型,== 比较的是两个引用是否指向同一个对象;判断字符串的内容是否相同,通常使用 equals() 方法。
逻辑运算符
基本逻辑运算符
假设要判断一个整数 x 是否大于 5 且小于 15。数学中可以写成 5 < x < 15,但在 Java 中不能直接照搬这种链式比较,需要分别写出两个条件,再用逻辑运算符连接:
x > 5 && x < 15
当 x > 5 和 x < 15 都为 true 时,条件才成立。这里使用的是短路与 &&,后面会讲它与 & 的区别。
| 运算符 | 作用 | 结果规则 |
|---|---|---|
& | 逻辑与 | 两边都为 true,结果才为 true |
| | 逻辑或 | 只要有一边为 true,结果就是 true |
^ | 逻辑异或 | 两边不同为 true,相同为 false |
! | 逻辑非 | 对一个布尔值取反 |
下面的代码分别展示了逻辑与、逻辑或、逻辑异或和逻辑非:
public class Test1 {
public static void main(String[] args) {
System.out.println(true & false);//false
System.out.println(true | false);//true
System.out.println(true ^ true);//false
System.out.println(!true);//false
}
}短路逻辑运算符
比如我们写一个登录程序,想先检查用户名是否存在、格式是否正确,再继续检查密码。如果用户名这一关就没通过,后面很多判断是不是就没必要继续做了?短路逻辑运算符就是这样:左侧条件已经能决定最终结果时,右侧表达式就不会执行。
| 运算符 | 作用 | 何时跳过右侧表达式 |
|---|---|---|
&& | 短路与 | 左侧为 false |
|| | 短路或 | 左侧为 true |
对于布尔值,&& 与 & 的真假规则相同,|| 与 | 的真假规则也相同;关键区别是 && 和 || 可能不执行右侧表达式,而 & 和 | 会计算两侧。
public class Test1 {
public static void main(String[] args) {
int a = 10;
// 短路或,左边为true,整个表达式既为真
// 右边不会进行判断和运算,a还是10
boolean b = true || (a++ > 0);
System.out.println(a);// 10
// 短路与,左边条件为假,整个表达式既为假
// 右边不会进行判断和运算,a还是10
b = false && (a++ < 0);
System.out.println(a);// 10
}
}true || (a++ > 0) 的左侧已经为 true,所以右侧不会执行;false && (a++ < 0) 的左侧为 false,右侧同样会被跳过。因此,两次输出的 a 都是 10,右侧的 a++ 没有发生。
三元运算符
条件运算符 ?: 可以根据一个布尔表达式,从两个表达式中选择一个结果,基本形式为:
条件表达式 ? 表达式1 : 表达式2
条件为 true 时取表达式 1 的结果,否则取表达式 2 的结果。例如,要比较两个整数的大小,并把较大的值赋给 c:
public class Test1 {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = a > b ? a : b;
System.out.println(c);//20
}
}可以把 a > b ? a : b 读成一个问题:“a 比 b 大吗?”如果是,就取 a;如果不是,就取 b。这里 a = 10、b = 20,显然不满足 a > b,所以最后把 20 赋给 c。
运算符优先级
Java 表达式中的运算符有优先级,例如乘除的优先级高于加减。下面按从高到低的顺序整理常见运算符,数字越小表示优先级越高。
| 优先级 | 运算符 | 说明 |
|---|---|---|
| 1 | .、()、[] | 成员访问、方法调用、数组下标 |
| 2 | a++、a-- | 后置自增、自减 |
| 3 | ++a、--a、!、~、一元 + 和 -、(类型) | 前置运算、取反、类型转换 |
| 4 | *、/、% | 乘、除、取余 |
| 5 | +、- | 加、减 |
| 6 | <<、>>、>>> | 移位 |
| 7 | <、<=、>、>=、instanceof | 大小比较、类型判断 |
| 8 | ==、!= | 相等比较 |
| 9 | & | 按位与 / 布尔逻辑与 |
| 10 | ^ | 按位异或 / 布尔逻辑异或 |
| 11 | | | 按位或 / 布尔逻辑或 |
| 12 | && | 短路与 |
| 13 | || | 短路或 |
| 14 | ?: | 三元运算符 |
| 15 | =、+=、-=、*=、/=、%= 等 | 赋值 |
例如 2 + 3 * 4,会先算乘法,得到 14;如果想先算加法,就写成 (2 + 3) * 4,结果是 20。
不确定表达式如何结合时,可以使用小括号明确计算顺序。例如 (2 + 3) * 4,一眼就能看出先计算加法。实际写代码时,比起硬背整张表,保证表达式容易理解更重要。
原码、反码与补码
理解位运算前,可以先看看有符号整数如何用二进制表示。下面用 8 位二进制演示原码、反码和补码的计算过程。Java 的 byte 为 8 位,int 为 32 位;具体到 Java 的运算时,还需要按实际的数据类型判断位宽。
原码
原码(符号和数值分开表示)把最高位作为符号位:0 表示正数,1 表示负数,其余位记录数值的大小。
以 8 位为例:
15的原码是0000 1111。-1的原码是1000 0001。- 正数的最大值为
0111 1111,即127;负数的最小值为1111 1111,即-127。
原码还存在两种零:0000 0000 表示 +0,1000 0000 表示 -0。
0000 00011000 00010000 00001000 0000红色数字是符号位;后面 7 位记录数值大小。
如果直接把原码当作普通二进制数相加,就会出现问题。比如 -1 + 1 应该为 0,但直接相加得到 1000 0010,按原码解释却是 -2。也就是说,原码直接按普通二进制加法计算,并不能正确处理这种正负数相加的情况。
反码
我们前面试过,原码直接用普通二进制加法处理负数会得到错误结果。为了让负数也能参与计算,可以尝试另一种表示方法:反码。
反码的规则并不复杂:正数保持不变;负数在原码的基础上保留符号位,将后面的数值位取反,也就是 0 变 1、1 变 0。例如:
-1的原码是1000 0001,反码是1111 1110。-2的原码是1000 0010,反码是1111 1101。
还记得刚才 -1 + 1 得不到零的问题吗?现在用反码试一下:1111 1110 + 0000 0001 = 1111 1111。在反码表示中,1111 1111 对应的是 -0,所以这个结果的数值确实是 0。
不过,反码有两个零:0000 0000 表示 +0,1111 1111 表示 -0。这就引出了另一个有意思的问题:如果一个负数加上正数,结果跨过了零,会怎么样?
例如 -2 + 5,我们知道答案应该是 3。但把 -2 的反码 1111 1101 和 5 的二进制 0000 0101 直接相加,会得到:
-
1111 1101 + 0000 0101 = 1 0000 0010。 -
如果像普通固定宽度二进制加法那样直接丢弃最左边的进位,只留下
0000 0010,得到的却是2。
为什么少了 1? 从反码有 +0、-0 两种表示这个特点来理解,就好像跨过零时还多经过了一个零。但要注意,这只是帮助我们理解现象的直观说法,并不代表反码本身算错了。
反码加法有自己的规则:最高位产生的进位要重新加回最低位,这叫“循环进位”。刚才多出来的最高位是 1,把它加回去,0000 0010 + 1 = 0000 0011,得到的就是正确答案 3。
1111 11010000 01011 0000 00100000 0010 + 10000 0011只丢弃进位会得到 2;按反码的循环进位规则把它加回去,最终得到 3。
也就是说,反码已经能够表示和计算负数,只是需要额外处理循环进位,而且一个零还有两种表示。能不能让零只有一种表示,同时又让二进制加法更简单呢?这就要用到补码了。
补码
补码可以在负数的反码基础上再加 1 得到。正数的补码仍然和普通二进制写法一样。先看两个例子:
-1:原码1000 0001→ 反码1111 1110→ 补码1111 1111。-2:原码1000 0010→ 反码1111 1101→ 补码1111 1110。
你可以把这个变化理解成:把负数在反码中的表示整体往后移动了一位。特别是原来反码中的 -0,它的编码为 1111 1111,再加 1 后只保留低 8 位,就变成了 0000 0000,和 +0 使用同一种表示了。
再拿刚才的 -2 + 5 试试。-2 的补码是 1111 1110,加上 0000 0101:
1111 1110 + 0000 0101 = 1 0000 0011
这一次直接舍弃超出 8 位的最高位,留下 0000 0011,结果就是 3,不需要再把进位绕回来加一次。
1111 11100000 01011 0000 00110000 0011补码进行固定宽度加法时,丢弃超出位宽的进位即可,不需要循环进位。
补码还有一个比较特别的地方:在 8 位补码中,1000 0000 表示 -128,所以它的取值范围是 -128~127。8 位原码、反码只能表达最低到 -127 的负数,而补码把原本重复表示零的一个编码利用了起来。
Java 的 byte、short、int、long 都使用补码表示有符号整数。理解了补码,再去看负数的位运算和移位运算就容易多了。
按位运算与移位运算
&、|、^ 既可以作用于 boolean 值,也可以用于整数。用于整数时,它们会按二进制位分别进行计算。
| 运算符 | 作用 | 基本规则 |
|---|---|---|
& | 按位与 | 对应位都为 1 才得到 1 |
| | 按位或 | 对应位有一个为 1 就得到 1 |
^ | 按位异或 | 对应位不同得到 1 |
~ | 按位取反 | 将每一位的 0 与 1 互换 |
<< | 左移 | 位整体向左移动,右侧补 0 |
>> | 有符号右移 | 位整体向右移动,左侧补符号位 |
>>> | 无符号右移 | 位整体向右移动,左侧补 0 |
例如 3 & 5,先把两个正数写成二进制,再把每一位对齐计算:
0000 00110000 01010000 0001只有两个数的对应位都是 1 时,该位结果才是 1。
类似地,3 | 5 的结果为 7(0000 0111),3 ^ 5 的结果为 6(0000 0110)。按位或只要一边是 1 就留下 1;按位异或则是两个对应位不同才留下 1。~ 会把每一位取反,例如 Java 中 ~3 的结果是 -4,因为实际参与计算的是 32 位补码。
遇到负数时,需要按补码理解它的二进制位。例如计算 -3 >> 2:
-3的 8 位补码示意为1111 1101。- 向右移动两位,高位补
1,得到1111 1111。 - 这个补码对应的数是
-1,所以-3 >> 2的结果为-1。
1111 11011111 11101111 1111蓝色位表示从左侧补入的 1;得到的 8 位补码 1111 1111 表示 -1。
上面的图使用 8 位来展示补位过程。在 Java 中,-3 的类型是 int,实际右移发生在 32 位二进制上;由于高位同样补 1,结果仍是 -1。
>>> 会从高位补 0。例如,int 类型的 -3 >>> 2 按 32 位计算,结果为 1073741823。
11111111 11111111 11111111 1111110100111111 11111111 11111111 11111111左边补入两个 0,按 32 位计算得到正数 1073741823。
处理负数位移时,关键是看补码的位模式:>> 在左侧补符号位,>>> 则补 0,因此二者可能得到完全不同的结果。
还有一点:对于 int 和 long,位移操作会分别按 32 位或 64 位进行;byte、short、char 参与位移时会先提升为 int。左移时如果高位被移出,数据也可能丢失,因此不能简单地认为左移一定等于乘以 2 的某次方。
聊两句
评论审核后显示有疑问、补充,或者想交流一下,都可以写在这里。
评论区将在滚动到这里时加载。