# Java教程 - 3 运算符
在编写有逻辑的代码前,先学习一下 Java 中的运算符。
下面介绍 Java 中常见的运算符:算数运算符、赋值运算符、关系运算符。
# 3.1 算数运算符
算数运算符是干嘛的?
就是进行数学运算的,就是小学学的加、减、乘、除等。
Java 中常见的算数运算符如下:
运算符 | 描述 | 示例 |
---|---|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取余,模运算 | a % b |
举个例子:
public class HelloJava {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println(a + b); // 输出 13
System.out.println(a - b); // 输出 7
System.out.println(a * b); // 输出 30
System.out.println(a / b); // 输出 3
System.out.println(a % b); // 输出 1
}
}
2
3
4
5
6
7
8
9
10
11
12
注意:两个整数相除,结果还是整数,小数部分会被去掉。
如果想让两个整数相除,保留小数部分,可以先乘上1.0,举个栗子:
int a = 10;
int b = 3;
System.out.println(1.0 * a / b); // 输出 3.3333333333333335
2
3
4
加减乘除在运算中用的是最多的,但是模运算有时候也会用到,下面举个栗子:
求1789的十位数是多少?
int i = 1789;
int j = i / 10 % 10;
System.out.println(j); // 结果为:8
2
3
因为 i
是整形的,所以 i / 10
只会保留整数部分,得到 178
,178 % 10
,余数是 8
。
同样,如果判断一个整数是否是偶数,那么可以将这个数 % 2,然后查看结果是否是 0,如果是 0 就是偶数,否则是奇数。
算数运算符也是有优先级的,和在小学的时候学习的一样。
int i = 3 + 2 * 4;
System.out.println(i); // 结果为:11
2
乘、除、取模运算的优先级大于加、减运算。
# 3.2 赋值运算符
赋值运算符就是用来给变量赋值的。
# 赋值运算符
运算符 | 描述 | 举例 |
---|---|---|
= | 赋值运算符 | 就是把 = 右边的值赋值给左边的变量,之前用过了。 |
例如:
int a = 2;
int b = 3;
int c = a + b;
2
3
除了赋值运算符,下面还有复合赋值运算符。
# 复合赋值运算符
复合赋值运算符就是经过计算后,将值赋给前面的变量。
Java 中常用的复合赋值运算符如下:
运算符 | 描述 | 举例 |
---|---|---|
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模赋值运算符 | c %= a 等效于 c = c % a |
~/= | 整除赋值运算符 | c ~/= a 等效于 c = c ~/ a |
举个栗子:
public static void main(String[] args) {
int a = 5;
int b = 3;
a += b; // a = a + b
System.out.println(a); // 8
a = 5;
a -= b; // a = a - b
System.out.println(a); // 2
a = 5;
a *= b; // a = a * b
System.out.println(a); // 15
}
2
3
4
5
6
7
8
9
10
11
12
13
14
复合赋值运算符感觉这么写可读性还变差了,有什么好处呢?
- 更加简练;
- 避免类型转换的麻烦;
是如何避免类型转换的,举个栗子:
short s = 10;
// s = s + 2; // 编译失败,因为得到的结果是int类型,无法赋值给short
s += 2; // 可以,复合赋值运算符不会改变变量本身的数据类型
System.out.println(s); // 12
2
3
4
复合赋值运算符运算完成,类型是不变的,如果使用普通方式,则需要强制转换 s = (short)(s + 2)
。
# 3.3 自增自减运算符
Java中的自增自减运算符包括++
和--
。它们可以用于对变量进行加1或减1操作。
举个栗子:
public static void main(String[] args) {
int a = 5;
a++; // a自增1
System.out.println(a); // 输出 6
a--; // a自减1
System.out.println(a); // 输出 5
}
2
3
4
5
6
7
需要注意的是,自增自减运算符可以放在变量的前面或后面,这会影响到表达式的值。
如果运算符放在变量的前面,表示先加减,后使用;如果运算符放在变量的后面,表示先使用,后加减。
举个栗子:
public static void main(String[] args) {
int a = 5;
int b = a++; // 先使用a的值还是5,后加1,a的值变为6
System.out.println(b); // 5
System.out.println(a); // 6
int c = 5;
int d = ++c; // 先加减c+1变为6,后使用,d的值为6
System.out.println(d); // 6
System.out.println(c); // 6
}
2
3
4
5
6
7
8
9
10
11
--
操作符也是一样的。
++
和 --
运算符也不会改变变量的数据类型,举个栗子:
short s = 10;
short t = s ++; // 仍然是short类型
System.out.println(t); // 11
2
3
# 3.4 关系运算符
关系运算符也就是比较运算符,主要有以下几种:
运算符 | > | < | >= | <= | == | != |
---|---|---|---|---|---|---|
含义 | 大于 | 小于 | 大于等于 | 小于等于 | 等于 | 不等于 |
举个栗子:
public static void main(String[] args) {
int a = 10;
int b = 3;
boolean c = a == b; // 将比较运算的结果赋值给c
System.out.println(c); // false
boolean d = a > b; // 将比较运算的结果赋值给c
System.out.println(d); // true
System.out.println(a != b); // true
System.out.println(a < b); // false
System.out.println(a >= b); // true
System.out.println(a <= b); // false
String str1 = "Doubi";
String str2 = "Doubi";
System.out.println(str1.equals(str2)); // true
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
关系运算符得到的结果都是 boolean
类型,在后面可以通过使用关系运算符来进行条件的判断。例如身高大于120cm就要买儿童票等场景。
这里需要注意,如果比较两个字符串是否相等,不要使用 ==
运算符,要使用 equals()
方法。
因为字符串是引用类型,对于引用类型,==
运算符比较的是两个变量内存地址是否相同,而不是比较对象的内容。
# 3.5 逻辑运算符
# 1 逻辑运算符
主要有以下三种:
运算符 | && | || | ! |
---|---|---|---|
含义 | 与,两边条件同时满足 | 或,两边条件满足一个即可 | 非,取反值,真为假,假为真 |
举个栗子:
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println(a && b); // false
System.out.println(a || b); // true
System.out.println(!a); // false
}
2
3
4
5
6
7
逻辑运算符两边必须是 boolean 类型的变量或结果为 boolean 类型的表达式。
逻辑运算符得到的结果还是 boolean 类型,可以赋值给 boolean 类型的变量。
再举个例子:
public static void main(String[] args) {
int a = 3;
int b = 12;
System.out.println(a > 5 && b > 10); // false
System.out.println(a > 5 || b > 10); // true
System.out.println(!(a > 5)); // true
}
2
3
4
5
6
7
8
!(a > 5)
是将 a > 5
的结果取反。 a > 5
结果为 false
,取反则为 true
。
# 2 逻辑运算符的优先级
优先级:!
> &&
> ||
举个栗子:
public static void main(String[] args) {
int a = 3;
int b = 12;
int c = 6;
int d = 10;
System.out.println(a > 5 && b > 10 || c > 5 && d > 10); // false
}
2
3
4
5
6
7
当一个逻辑运算语句中同时包含与、或 、 非运算的时候,会按照优先级进行运算。
所以上面先运算 a > 5 && b > 10
,然后运算 c > 5 && d > 10
,最后运算 ||
两边的结果。
再举个例子:
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean result = !a || a && b;
System.out.println(result); // false
}
2
3
4
5
6
7
先运算 !a
,结果为 false
,然后运算 a && b
,结果为 false
,最后运算 ||
两边的结果,为 false
。
如果搞不清楚先后运算的顺序,就用括号 ()
括起来,准没错。
# 3 逻辑短路
逻辑短路就是在进行逻辑运算的时候,如果已经能够得到最后的值,就不会再继续进行判断了。
只有 与运算符 &&
和 或运算符 ||
存在逻辑短路。
举个栗子:
public static void main(String[] args) {
int num = 10;
boolean b = num > 20 && num++ < 40;
System.out.println(num); // 10
}
2
3
4
5
在执行上面代码的时候,num > 20
已经不成立了,而 &&
运算需要两边都满足,所以后面的条件成不成立都不会影响最终逻辑表达式的结果,所以 &&
后面的 num++ < 40
就不会再继续执行了,那么 num
的值就没有 ++
,这就是逻辑短路。
同样 || 运算符:
public static void main(String[] args) {
int num = 10;
boolean b = num < 20 || num++ > 40;
System.out.println(num); // 10
}
2
3
4
5
在执行上面代码的时候,num < 20
已经成立了,||
运算只要一边满足即可,所以整个逻辑表达式肯定是成立的,所以 ||
后面的 num++ > 40
就不会继续执行了,那么 num
的值就没有 ++
。
如果不想逻辑短路,可以使用 &
、|
运算符,一个&
或 |
时,左边无论真假,右边都进行运算。
以逻辑与,修改上面的代码:
public static void main(String[] args) {
int num = 10;
boolean b = num > 20 & num++ < 40;
System.out.println(num); // 11
}
2
3
4
5
使用 &
运算符,就不存在逻辑短路问题,无论左边的运算结果为 true
或 false
,右边都会执行运算。
&
、|
运算符用的不多,开发中主要使用 &&
和 ||
。
# 3.6 位运算符
位运算符在实际的开发中用的不多,在底层代码中会用到,这里了解一下即可。
位运算符允许你直接操作数据的二进制表示形式的各个位。这些运算符可以用于执行各种位级操作,如按位与、按位或、按位取反和按位移动等。位运算符都是对整数类型(如int、long等)进行操作。
建议先学习一下本站的 计算机基础知识 (opens new window) 教程。
1.左移(<<)
- 符号:
<<
- 作用: 将操作数的所有位向左移动指定的位数,包括符号位,右侧空出的位用0填充。
举个栗子:
public static void main(String[] args) {
int i = 1;
int j = i << 2;
System.out.println(j); // 4
}
2
3
4
5
1
的 int 类型,4个字节存储,二进制表示为00000000 00000000 00000000 00000001
,左移两位,变为 00000000 00000000 00000000 00000100
,即为4,左移后,右侧补0。
所以左移n位时候,相当于乘上 2^n
次幂。
- 右移(>>)
- 符号:
>>
- 作用: 将操作数的所有位向右移动指定的位数,左侧空出的位使用符号位(正数用0填充,负数用1填充)进行填充。
举个栗子:
public static void main(String[] args) {
int i = -7;
int j = i >> 2;
System.out.println(j); // -2
}
2
3
4
5
-7
的二进制表示是 11111111 11111111 11111111 11111001
,右移两位,右侧被移除两位,变为 11111111 11111111 11111111 11111110
,也就是 -2
。
- 无符号右移(>>>)
- 作用: 将操作数的所有位向右移动指定的位数(包括符号位),左侧空出的位使用0填充。
举个栗子:
public static void main(String[] args) {
int i = -7;
int j = i >>> 2;
System.out.println(j); // 1073741822
}
2
3
4
5
-7
的二进制表示是 11111111 11111111 11111111 11111001
,右移两位,包括符号位,右侧被移除两位,变为 00111111 11111111 11111111 11111110
,也就是 1073741822
。
注意:是没有 <<<
运算符的。
- 按位与(&)
- 符号:
&
- 作用: 对两个操作数的每一个位执行逻辑与操作,只有两个位都为1时结果才为1,否则为0。
举个栗子:
public static void main(String[] args) {
int a = 15; // 二进制表示为 1111
int b = 9; // 二进制表示为 1001
// 按位与
int resultAnd = a & b; // 结果为 9 (0000 1001)
System.out.println("按位与结果:" + resultAnd);
}
2
3
4
5
6
7
8
每一位进行与
操作,并得到结果:
00000000 00000000 00000000 00001111
& 00000000 00000000 00000000 00001001
= 00000000 00000000 00000000 00001001 = 9
2
3
- 按位或(|)
- 符号:
|
- 作用: 对两个操作数的每一个位执行逻辑或操作,只要两个位中有一个为1,结果就为1。
举个栗子:
public static void main(String[] args) {
int a = 15; // 二进制表示为 1111
int b = 9; // 二进制表示为 1001
// 按位或
int resultOr = a | b; // 结果为 15 (0000 1111)
System.out.println("按位或结果:" + resultOr);
}
2
3
4
5
6
7
8
每一位进行或
操作,并得到结果:
00000000 00000000 00000000 00001111
| 00000000 00000000 00000000 00001001
= 00000000 00000000 00000000 00001111 = 15
2
3
- 按位异或(^)
- 符号:
^
- 作用: 对两个操作数的每一个位执行异或操作,两个位相同则结果为0,不同则结果为1。
举个栗子:
public static void main(String[] args) {
int a = 15; // 二进制表示为 1111
int b = 9; // 二进制表示为 1001
// 按位异或
int resultXor = a ^ b; // 结果为 6 (0000 0110)
System.out.println("按位异或结果:" + resultXor);
}
2
3
4
5
6
7
8
每一位进行异或
操作,并得到结果:
00000000 00000000 00000000 00001111
| 00000000 00000000 00000000 00001001
= 00000000 00000000 00000000 00000110 = 6
2
3
- 按位取反(~)
- 符号:
~
- 作用: 对操作数的每一个位执行取反操作(包括符号位),将每个1变为0,每个0变为1。
举个栗子:
public static void main(String[] args) {
int a = 15; // 二进制表示为 1111
// 按位取反
int resultNotA = ~a; // 结果为 -16 (1111 0000)
System.out.println("按位取反结果:" + resultNotA);
}
2
3
4
5
6
7
每一位进行取反
操作,并得到结果:
00000000 00000000 00000000 00001111
~= 11111111 11111111 11111111 11110000 = -16
2
上面的运算了解一下就好了,实际开发中不涉及底层的,基本用不到。
# 3.7 运算符优先级
上面那么多运算符,如果同时运算的时候,优先级是怎么样的呢?
举个栗子:
public static void main(String[] args) {
int a = 5;
int b = 10;
int c = 15;
int d = 5;
int e = 25;
int f = 2;
int g = 3;
int h = 40;
int i = 1;
int j = 2;
boolean m = a + b * c / d - e << f >>> g > 0 && h >> i * j > 0;
System.out.println(m);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
看着上面的代码,眼不眼晕。在实际的开发中,不要这样写,可读性太差了。
在 Java 中运算符的优先级,按照高到低的顺序如下:
优先级 | 运算符 | 分类 |
---|---|---|
1 | ++ , -- | 递增/递减 |
2 | * , / , % | 乘法、除法和取模 |
3 | + , - | 加法和减法 |
4 | << , >> , >>> | 位移运算 |
5 | < , <= , > , >= | 比较运算 |
6 | == , != | 相等和不等运算 |
7 | & | 按位与 |
8 | ^ | 按位异或 |
9 | | | 按位或 |
10 | && | 逻辑与 |
11 | || | 逻辑或 |
12 | ?: | 条件运算符,后面讲解 |
13 | = , += , -= , *= , /= , %= | 赋值运算符 |
所以上面的代码,根据优先级括号,应该是这样的:
boolean m = (((a + (b * c / d) - e) << f) >>> g) > 0 && (h >> (i * j)) > 0;
在开发中,不知道优先级高低,添加括号就可以了。