入门篇-其之六-Java运算符(中)
祝所有程序员,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;反之,结果为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. 位运算符只有在计算机底层开发或者在性能等关键领域开发会用到。
入门篇-其之六-Java运算符(中)的更多相关文章
- C#入门篇-4:使用运算符
using System; using System.Text; using System.Collections; using System.Collections.Generic; using S ...
- JS基础入门篇(七)—运算符
1.算术运算符 1.算术运算符 算术运算符:+ ,- ,* ,/ ,%(取余) ,++ ,-- . 重点:++和--前置和后置的区别. 1.1 前置 ++ 和 后置 ++ 前置++:先自增值,再使用值 ...
- 前端向后台的华丽转身 — PHP入门篇
三个月就这么悄悄溜走了,本K对于前端虽然有了一定的认识,但对一些方面还是处于一种比较萌币的状态,就在这种萌币状态下,本K又跟着大神浩开始了后台语言-PHP语言的学习.PHP的学习对于学过其他语言的人来 ...
- Java总结篇系列:Java多线程(三)
本文主要接着前面多线程的两篇文章总结Java多线程中的线程安全问题. 一.一个典型的Java线程安全例子 public class ThreadTest { public static void ma ...
- Swift入门篇-swift简介
潜水博客园很多年,闲来无事,聊一下自己的经历,语文不好(如有什么错别字,请您在下评论)望您谅解,没有上过什么学的 在前期 ios入门篇 -hello Word(1) 文章中介绍我这半年准备写一些ios ...
- Java中的IO流 - 入门篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的IO流-入门篇>,希望对大家有帮助,谢谢 由于Java的IO类有很多,这就导致我刚开始学的时候,感觉很乱,每次用到都是上网搜,结果 ...
- Java中的集合List - 入门篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的集合List - 入门篇>,希望对大家有帮助,谢谢 简介 说实话,Java中的集合有很多种,但是这里作为入门级别,先简单介绍第一种 ...
- Java中的映射Map - 入门篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的映射Map - 入门篇>,希望对大家有帮助,谢谢 简介 前面介绍了集合List,这里开始简单介绍下映射Map,相关类如下图所示 正 ...
- Java中的集合Set - 入门篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的集合Set - 入门篇>,希望对大家有帮助,谢谢 简介 前面介绍了集合List,映射Map,最后再简单介绍下集合Set,相关类如下 ...
- 《Java从入门到放弃》入门篇:hibernate中的多表对应关系
hibernate中的对应关系其实就是数据库中表的对应关系, 就跟某些电影中的某些场景是一样一样滴. 比如可以是一男一女,还可以是一男多女, 更可以是多男一女,最后最后最后还可以是多男多女!!! 有些 ...
随机推荐
- Pycharm里Python运行窗口显示乱码���的解决方法
当你的Python程序运行后,会在运行窗口中显示乱码 ��� 等字样,如下 原因是 Pycharm中默认设置只显示UTF-8编码的格式,需要修改支持显示中文支持. 解决方法: 菜单中选择 File S ...
- 为什么 kubelet 不使用容器化部署?
每日一问系列 为什么 kubelet 不使用容器化部署? 通过脚本(shell/ansible 等)在节点上部署 kubelet 服务时,涉及 kubelet 进程 service 启动配置.证书等, ...
- Java stream流使用
1.使用filter()过滤List //查找身高在1.8米及以上的学生 List<StudentInfo> boys = studentList.stream().filter(s-&g ...
- Smali语言
什么是Smali smali语言是Davlik的寄存器语言,语法上和汇编语言相似,DalvikVM与JVM的最大的区别之一就是DalvikVM是基于寄存器的.基于寄存器的意思是,在smali里的所有操 ...
- 【go语言】1.2.1 Go 环境安装
Go 语言的安装过程非常简单,无论你使用的是哪种操作系统,都可以按照下面的步骤来进行. Windows 系统 前往 Go 语言的官方下载页面:https://golang.org/dl/ 根据你的操作 ...
- 自用 .net C# CSV文件写入读取工具类
using System.Data; using System.IO; using System.Linq; using System.Text; using System.Text.RegularE ...
- OpenLayers示例
http://develop.smaryun.com:81/API/JS/OL3InterfaceDemo/index.htm
- GPT-4助力数据分析:提升效率与洞察力的未来关键技术
摘要 随着大数据时代的到来,数据分析已经成为企业和组织的核心竞争力.然而,传统的数据分析方法往往无法满足日益增长的数据分析需求的数量和复杂性.在这种背景下,ChatGPT-4作为一种先进的自然语言处理 ...
- Python生成30万条Excel 测试数据
使用Python生成30万条Excel 测试数据 from openpyxl import Workbook from concurrent.futures import ThreadPoolExec ...
- 利用CI机制管控jar依赖树
1. 现状·问题 你还记得你排查jar冲突的付出么? 为了有效控制jar包更新带来的未知jar引入和变动,我们经常使用dependency-tree来查看依赖关系排查问题,通常是出现问题再被动分析和排 ...