祝所有程序员,1024节日快乐!!!😄🤣😏😂😎
一、自增/自减运算符
假设有一个变量intValue
的值为10,如果想让这个值加1,有哪些方式?
首先,我们可以使用最原始的方式:
int intValue = 10; intValue = intValue + 1;
或者使用赋值运算符+=
操作:
int intValue = 10; intValue += 1;
正如这一节的标题名称自增/自减运算符,我们可以使用自增运算符来解决上述的问题。
1.1 自增/自减运算符的基本使用
自增运算符使用变量名++(也叫后缀自增,因为++
在变量名后面)或者++变量名(也叫前缀自增,因为++
在变量名前面)的方式表示,二者最终都会将变量的值加1。
同理,自减运算符使用变量名--(也叫后缀自减,因为--
在变量名前面)或者--变量名(也叫前缀自减,因为--
在变量名前面)的方式表示,二者最终都会将变量的值减1。
以下是使用自增运算符解决上述问题的代码案例:
/** * 自增自减运算符 * * @author iCode504 * @date 2023-10-11 7:38 */ public class IncrementAndDecrementOperators { public static void main(String[] args) { // 后缀自增i++和前缀自增++i简单使用 int intValue1 = 1; intValue1++; int intValue2 = 1; ++intValue2; System.out.println("intValue1 = " + intValue1); System.out.println("intValue2 = " + intValue2); // 后缀自减i--和前缀自减--i简单使用 int intValue3 = 2; intValue3--; int intValue4 = 2; --intValue4; System.out.println("intValue3 = " + intValue3); System.out.println("intValue4 = " + intValue4); } }
运行结果:
i++
或者++i
二者执行完表达式计算以后,i
的值自增1(同理,i--
或--i
得到的结果是i
自减1)。
1.2 前缀自增(减)和后缀自增(减)的区别
后缀自增i++
,先返回变量i
的当前值,运算完成后再将i
增加1。例如:j = i++ * 2
,此时右侧表达式计算时得到的是当前i
的值,在右侧表达式运算完成后,i
再自增1。
前缀自增++i
,先将i
的值增加1,然后返回变量i
的当前值。例如:j = ++i * 2
,此时右侧表达式计算时得到的是i
加1之后的值,在右侧表达式运算完成后,i
的值也就是前面自增1的结果。
接下来我们使用代码来测试一下:
/** * i++和++i的区别 * * @author iCode504 * @date 2023-10-16 22:39 */ public class IncrementAndDecrementOperators1 { public static void main(String[] args) { int intValue1 = 10; int intValue2 = 10; int intValue3 = 10; int intValue4 = 10; int result1 = intValue1++; int result2 = ++intValue2; System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); // 执行完赋值操作后,两个变量值最后都会自增1,此时得到的结果都是11 System.out.println("intValue1 = " + intValue1); System.out.println("intValue2 = " + intValue2); int result3 = intValue3++ * 2; // 计算时先赋值为intValue3的值,计算完成后intValue3的值自增1 int result4 = ++intValue4 * 2; // 计算时先将intValue4的值自增1,计算完成后将自增的值赋值给intValue4 System.out.println("result3 = " + result3); System.out.println("result4 = " + result4); } }
运行结果:
关于i++
和++i
在字节码层面的区别,请查看这篇文章:点我查看
二、比较运算符
和数学学过的一样,Java的比较运算符有如下:大于>
,小于<
,等于==
,大于等于>=
,小于等于<=
,不等于!=
。
比较运算符得到的结果是布尔类型的值,即true
或false
。
/** * 比较运算符的使用 * * @author iCode504 * @date 2023-10-11 23:05 */ public class ComparisonOperator { public static void main(String[] args) { int intValue1 = 30; int intValue2 = 20; System.out.println("intValue1 > intValue2: " + (intValue1 > intValue2)); // > 大于 System.out.println("intValue1 < intValue2: " + (intValue1 < intValue2)); // < 小于 System.out.println("intValue1 == intValue2: " + (intValue1 == intValue2)); // == 等于 System.out.println("intValue1 != intValue2 = " + (intValue1 != intValue2)); // != 不等于 System.out.println("intValue1 >= intValue2: " + (intValue1 >= intValue2)); // >= 大于等于 System.out.println("intValue1 <= intValue2: " + (intValue1 <= intValue2)); // <= 小于等于 } }
运行结果:
三、逻辑运算符
逻辑运算符只能用在布尔值或者计算结果是布尔值的表达式(例如:比较运算符得到的结果就是布尔值)。
3.1 逻辑与、逻辑或运算符
短路与使用&&
表示,格式是:布尔表达式1 && 布尔表达式2。如果&&
两侧得到的结果都是true
,那么得到的结果也是true
,否则其他情况均为false
。
短路或使用||
表示,格式是:布尔表达式1 || 布尔表达式2。如果||
只要有一侧为true
,那么得到的结果是true
,如果两侧结果都是false
,那么得到的结果也是false
。
以下是示例代码:
/** * 短路与&& 短路或|| 的使用 * * @author iCode504 * @date 2023-10-16 22:24 */ public class LogicOperators1 { public static void main(String[] args) { boolean result1 = 40 != 20; boolean result2 = 20 > 5; boolean result3 = 30 > 40; System.out.println("计算结果"); System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); System.out.println("result3 = " + result3); System.out.println("使用短路与&& 短路或|| 的运算结果: "); System.out.println("result1 && result2 = " + (result1 && result2)); System.out.println("result1 && result3 = " + (result1 && result3)); System.out.println("result2 && result3 = " + (result2 && result3)); System.out.println("result1 || result2 = " + (result1 || result2)); System.out.println("result1 || result3 = " + (result1 || result3)); System.out.println("result2 || result3 = " + (result2 || result3)); } }
运行结果:
运行结果符合我们的预期和上述的说明。
3.2 逻辑非运算符
非运算符使用!
表示,格式为:!布尔值
或者!布尔表达式
。
非运算符的作用是将得到的布尔值取反,例如:!true
的结果是false
,同理,!false
的结果是true
,以下是非运算符在代码中的使用:
/** * 逻辑非运算符! 的使用 * * @author iCode504 * @date 2023-10-16 22:13 */ public class LogicOperators2 { public static void main(String[] args) { boolean result1 = 20 >= 30; boolean result2 = 40 != 20; System.out.println("正常结果: "); System.out.println("result1 = " + result1); System.out.println("result2 = " + result2); System.out.println("取非运算符!得到的结果"); System.out.println("!result1 = " + !result1); System.out.println("!result2 = " + !result2); } }
运行结果:
从结果中我们可以看出,运算结果如果为true
,加上非运算符,得到的结果正好相反,为false
。同理,如果运算结果为false
,取非得到的结果是true
。
四、位运算符(了解即可)
位运算符主要是针对整型数字的二进制进行运算。在二进制的位运算中,1表示真,0表示假。
4.1 位与、位或、异或运算符
位运算符主要包含如下的运算符:
符号 | 名称 | 说明 |
---|---|---|
& |
位与运算符 | 如果相同位两个二进制数都为1,则结果为1;反之,结果为0。 |
| |
位或运算符 | 如果相同位两个二进制数都为0,则结果为0;反之,结果为1。 |
^ |
异或运算符 | 如果相同位两个二进制数相同,则结果为0;反之,结果为1。 |
~ |
非运算符 | 一元运算符,将每一位的二进制数由1变0,由0变1。 |
看完上述说明可能还是一头雾水,接下来以具体案例来说明它们是如何使用的。
假设有两个int
类型的整数,第一个值为8,另一个值是6,将其转换成32位(因为int
本身就是32位)的二进制整数为:
由于前24位(未标黄部分)都是0,为了直观展示上述运算符的运算过程,在后续计算中默认省略前24位:
按照位与&
的运算规则,在相同位上两个二进制数的值都为1,则结果为1,否则其他情况都为0,那么此时的运算过程为:
得到的结果为:
转换成十进制的结果就是0,8 & 6
的结果为0。
同理,按照位或|
的规则,如果相同位两个二进制数都为0,则结果为0;反之,结果为1。此时的运算过程为:
得到的结果:
转换成十进制就是14,因此8 | 6
的运算结果是14。
根据异或运算符的规则:如果相同位两个二进制数相同,则结果为0;反之,结果为1。此时的运算过程为:
得到的结果:
转换成十进制是14,因此8 ^ 6
得到的结果是14。
4.2 非运算符
此时我们再观察完整的8和6的二进制数(32位)
按照非运算符~
的规定,将每一位的二进制数由1变0,由0变1。此时~8
会转换成如下的形式:
二进制的第一位表示正负号,0表示正号,1表示负号,并且不参与运算。此时从~8
得到的二进制数来看,未来转换成十进制数字也是负数。
负数的二进制表示:除符号位以外,其他位取反操作(0变成1,1变成0),然后再加1以补码的方式表示。
此时~8
的结果就是补码,我们需要对上述操作进行逆向操作。
首先,将二进制数减1,得到如下结果(反码):
再将反码还原(1变成0,0变成1),得到如下结果:
此时除第一位是负数以外,再将得到的结果转换成十进制数为-9
,因此~8
的结果是-9
。
同理,~6
的结果是-7
我们使用代码来检测一下上述运算结果:
/** * 位运算符 & | ~的使用 * * @author iCode504 * @date 2023-10-13 6:09 */ public class ByteOperators1 { public static void main(String[] args) { int intValue1 = 8; int intValue2 = 6; int result1 = intValue1 & intValue2; System.out.println("intValue1 & intValue2 = " + result1); int result2 = intValue1 | intValue2; System.out.println("intValue1 | intValue2 = " + result2); int result3 = ~intValue1; int result4 = ~intValue2; System.out.println("~intValue1 = " + result3); System.out.println("~intValue2 = " + result4); } }
运行结果:
4.3 移位运算符
移位运算符的主要是针对二进制数向左或者向右移动n位。其中<<
称作有符号左移运算符,>>
称作有符号右移运算符。
以有符号左移运算符为例,它的使用格式是:操作数 << 左移位数,例如:3 << 4
的含义是将3的二进制数向左移动4位(第1位符号位除外)。以下是它的运算过程:
将3转换成32位二进制数,如下图所示:
移动原则是:向左移,最左边多出的位数舍去,右侧空缺使用0来补缺(负数使用1来补缺)。同理,向右移,最右边多出的位数舍去,左侧空缺使用0来补缺(负数使用1来补缺)。
3向左移动4位以后的情况如下图:
按照上述规则,将左侧多出的4位舍去,右侧空缺位置使用0补上,此时得到的结果是:
将得到的结果转换成十进制数是:
因此:3 << 4
得到的结果是48。
同理,右移运算符的使用格式是:操作数 >> 右移位数,例如:-20 >> 3
的含义是将-20的二进制数向右移动3位(第1位符号位除外)。以下是运算过程:
首先将-20转换成二进制形式表示(负数使用补码表示并参与计算):
-20向右移动3位以后的情况如下图所示:
此时空缺位使用1来补位(因为-20是负数),多余位舍去,得到如下的结果:
此时将负数的补码转换成原码的形式表示(原码和补码的知识可以查看这篇文章的原码、反码、补码:点我查看):
此时我们将原码转换成十进制表示:
因此-20 >> 3
得到的结果是-3。
前面我们提到的都是有符号移位。在Java中,还有一个无符号右移运算符,使用>>>
表示,格式是:操作数 >>> 向右移动数。
无符号右移运算符在向右移动时符号位和其他数字都参与移动。此时空缺位使用0来补齐即可。
这次我们让-20无符号右移3位,移动后的情况如下:
空缺位使用0补齐,多余位舍掉后的结果如下图:
使用计算器转换为十进制数字得到的结果如下图:
我们使用代码来验证一下上述推算过程得到的结果是否符合我们的预期:
/** * 位运算符 >> << 和 >>>的使用 * * @author iCode504 * @date 2023-10-16 7:31 */ public class ByteOperators2 { public static void main(String[] args) { int result1 = 3 << 4; int result2 = -20 >> 3; int result3 = -20 >>> 3; System.out.println("3 << 4 = " + result1); System.out.println("-20 >> 3 = " + result2); System.out.println("-20 >>> 3 = " + result3); } }
运行结果:
使用位运算符主要是针对整型数据的二进制值进行操作,由于位运算符直接操作二进制数值,执行效率非常高,远超普通的四则运算。但是为什么在日常开发中我们很少使用位运算符呢?
1. 首先,位运算符虽然执行效率非常高,但是可读性较差,容易让人困惑。例如:前面的-20 >> 3
的例子虽然在表面上是让-20向右移动3位,但是里面涉及到的过程是十分复杂的(负数由补码到反码,反码到补码就能让人焦头烂额)。
2. 大多数情况下我们都不需要直接操作二进制值。日常开发中,我们是直接针对数据做进一步处理即可,无需额外转换成二进制数据。
3. 位运算符只有在计算机底层开发或者在性能等关键领域开发会用到。