入门篇-其之六-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中的对应关系其实就是数据库中表的对应关系, 就跟某些电影中的某些场景是一样一样滴. 比如可以是一男一女,还可以是一男多女, 更可以是多男一女,最后最后最后还可以是多男多女!!! 有些 ...
随机推荐
- Unity UGUI的Text(文本)组件的介绍及使用
UGUI的Text(文本)组件的介绍及使用 什么是UGUI的Text(文本)组件? UGUI(Unity Graphic User Interface)是Unity引擎的一套用户界面系统,而Text( ...
- 手写raft(一) 实现leader选举
1. 一致性算法介绍 1.1 一致性同步与Paxos算法 对可靠性有很高要求的系统,通常都会额外部署1至多个机器为备用副本组成主备集群,避免出现单点故障. 有状态的系统需要主节点与备用副本间以某种方式 ...
- 详解TCP网络协议栈的工作原理
本文分享自华为云社区<网络通信的神奇之旅:解密Linux TCP网络协议栈的工作原理>,作者: Lion Long . 一.TCP网络开发API TCP,全称传输控制协议(Transmis ...
- MySQL的索引详解
在MySQL中,常见的索引类型有以下几种: B-Tree索引: B-Tree(Balanced Tree)索引是MySQL中最常见的索引类型.它基于B-Tree数据结构,适用于等值查询.范围查询和排序 ...
- zabbix6.4 邮件告警配置
1.注意事项 QQ邮箱不支持zabbix6以上邮件配置,报拒绝登录 建议使用163.com网易邮箱地址 2.添加媒介 创建媒介类型-> 3.添加用户 一般情况下,无需创建用户,编辑admin即可 ...
- [ansible]wget批量调用shell脚本
前言 相较于使用playbook,个人更习惯于编写shell脚本.如果需要多台服务器执行某一任务,可以将脚本放在某个http服务目录下,比如nginx,然后通过ansible的shell模块让服务器通 ...
- 一个 Java 接口快速开发框架:magic-api
一.简介 magic-api是一个基于Java的接口快速开发框架,编写接口将通过magic-api提供的UI界面完成,自动映射为HTTP接口.无需定义Controller.Service.Dao.Ma ...
- AtCoder ABC183F Confluence
题意 \(n\)个人,每个人属于一个班级\(ci\),这些人会有些小团体(并查集) 两种操作: \(1\) \(a\) \(b\),将\(a\)所在的集体和\(b\)所在的集体合并 \(2\) \(x ...
- 利用RATF框架实现web状态的监控
之前,我们已经说明了如何实现一个我们的接口测试框架RATF,当然这个框架不止可以用于管理我们的接口测试代码,我们还可以用他来对我们的web进行简单粗暴的监控. 原理: 1. 通过使用配置文件,对要监控 ...
- 在线问诊 Python、FastAPI、Neo4j — 创建 检查节点
目录 症状数据 创建节点 根据不同的症状,会建议做些相对应的检验.检查 症状数据 examine_data.csv 建议值用""引起来.避免中间有,号造成误识别 检查 " ...