运算符
算术运算符
二元运算符
- 二元运算符指的是需要两个操作数才能完成运算的运算符,例如:+,-,*,/,%。
- +号不但可以做加法运算,还可以表示正号和字符串连接符。
- 两个整数做除法(/)运算,结果只保留整数。
public class OperatorDemo { public static void main(String[] args) { // + 作为加法运算 int sum = 5 + 3; System.out.println("5 + 3 = " + sum); // + 作为正号 int positive = +sum; System.out.println("+sum = " + positive); // + 作为字符串连接符 String text = "result: " + sum; System.out.println(text); // 两个整数做除法 int a = 7; int b = 3; System.out.println("7 / 3 = " + (a / b)); // 只保留整数 } }
一元运算符
- 只需要一个操作数的运算符称为一元运算符,如:++,- - 等。
num++和++num,都等价于num = num + 1。++num先自增,后参与运算;num++先参与运算,后自增。num++和++num单独使用时没有区别,参与混合运算时,由于操作数栈和局部变量表的更新顺序不同,结果也不同。
可以对常量进行递增或递减操作吗?例如:
5++或++5。不能
public class ConstantIncrementDemo { public static void main(String[] args) { // 错误示例:常量不能递增 // 5++; // ++5; // 正确示例:变量可以递增 int num = 5; num++; // 后缀递增 System.out.println("After num++: " + num); // 输出 6 ++num; // 前缀递增 System.out.println("After ++num: " + num); // 输出 7 } }
int num = 5; num = num++;请问代码执行后num的值为多少?5
num++执行时,首先会取出num当前的值(即5),并将其压入操作数栈中。此时,操作数栈中有一个值:5。num++会执行自增操作,将num的值加 1,变为6。此时,栈中的5保持不变,而num的实际值已经变成了6。- 接下来,
num = num++中的num++会返回操作数栈中的值,即 原始值5。这时,赋值操作num = 5会将num设置为5,覆盖了先前自增后的值6。public class Main { public static void main(String[] args) { int num = 5; num = num++; // 后缀自增赋值 System.out.println(num); // 输出 5 } }
赋值运算符
=: 将右边的值赋给左边的变量。
扩展赋值运算符
- 扩展赋值运算符:是算术运算符和赋值运算符的结合。
- 扩展赋值运算符,会对计算结果自动进行转型。
运算符 用法举例 等效的表达式 += a += b a = a+b -= a -= b a = a-b *= a *= b a = ab /= a /= b a = a/b %= a %= b a = a%b
常见面试题
short num = 11; num = num + 1;和short num = 11; num += 1;哪一个正确呢?第2个正确,由于
num + 1的返回值类型是int,而扩展赋值运算符会对计算结果自动进行转型为short,而第一种方法不会自动转型,从而会导致类型不匹配。
int sum += 30;请问这行语句语法是否正确?不正确,等价于
int sum = sum + 30;,sum还未定义,不能使用。
比较运算符
比较运算符用来进行比较运算,运算结果是boolean类型。
比较运算符: >、 <、 >=、 <=、==、 !=
逻辑运算符
参与逻辑运算的数据类型必须为boolean类型,逻辑运算后的结果也为boolean类型。
与运算(&)
- 运算两边只要有一个为false,那么结果肯定为false。
- 只有运算两边都为true,那么结果才为true。
或运算(|)
- 运算两边只要有一个true,那么结果肯定为true。
- 只有运算两边都为false,那么结果才为false。
异或运算(^)
- 运算两边相同,那么结果肯定为false。
- 运算两边不同,那么结果肯定为true。
非运算(!)
!true == false;!false == true;
短路与(&&)
&&和&的运算结果是一样的,但是运算的过程有所不同。
&:无论左边的运算结果是什么,右边都需要参与运算。&&:
- 如果左边运算结果为false,那么右边就不需要参与运算了,直接返回结果false。
- 如果左边运算结果为true,那么需要进行右边的运算,并返回右边运算的结果。
public class Main { public static void main(String[] args) { int x = 5; // 使用 &,右边始终会执行 boolean result1 = (x > 10) & (++x > 5); System.out.println("& 运算结果: " + result1); System.out.println("x 的值(& 后): " + x); x = 5; // 重置 // 使用 &&,短路运算 boolean result2 = (x > 10) && (++x > 5); System.out.println("&& 运算结果: " + result2); System.out.println("x 的值(&& 后): " + x); } }
短路或(||)
||和|的运算结果是一样的,但是运算的过程有所不同。
|:无论左边的运算结果是什么,右边都需要参与运算。||:
- 如果左边运算结果为true,那么右边就不需要参与运算了,直接返回结果true。
- 如果左边运算结果为false,那么需要进行右边的运算,并返回右边运算的结果。
public class Main { public static void main(String[] args) { int x = 5; // 使用 |,右边始终会执行 boolean result1 = (x < 10) | (++x > 5); System.out.println("| 运算结果: " + result1); System.out.println("x 的值(| 后): " + x); x = 5; // 重置 // 使用 ||,短路运算 boolean result2 = (x < 10) || (++x > 5); System.out.println("|| 运算结果: " + result2); System.out.println("x 的值(|| 后): " + x); } }
位运算符
位运算符用于直接操作整数的二进制位。
<<左移
- 左移n位,等于在原数据上乘以2的n次方。
- 3*2可以使用
3 << 1来实现,这样做的效率更高。- 左移低位补0。
public class Main { public static void main(String[] args) { // 左移运算,8*2^2 = 32 System.out.println("8 << 2 = " + (8 << 2)); // 左移运算,-8*2^2 = -32 System.out.println("-8 << 2 = " + (-8 << 2)); } }
>>右移
- 右移n位,等于在源数据上除以2的n次方。
- 3/2可以使用
3 >> 1来实现,这样做的效率更高。- 正数则在高位补0,负数则在高位补1。
public class Main { public static void main(String[] args) { // 右移运算,8 / 2^2 = 2 System.out.println("8 >> 2 = " + (8 >> 2)); // 右移运算,-8 / 2^2 = -2 System.out.println("-8 >> 2 = " + (-8 >> 2)); } }
>>>无符号右移
- >>> 和 >> 移动类似,但是无论值的正负,都在高位补0 。
- ⚠️ 注意:没有无符号左移,因为左移本来就没有区分符号,符号位直接被覆盖。
public class Main { public static void main(String[] args) { int num1 = 8; // 正数 int num2 = -8; // 负数 // 原始二进制 System.out.println("8 的二进制: "); System.out.println(" " + String.format("%32s", Integer.toBinaryString(num1)).replace(' ', '0')); System.out.println("-8 的二进制: "); System.out.println(" " + String.format("%32s", Integer.toBinaryString(num2)).replace(' ', '0')); // 左移 int leftShift = num1 << 2; System.out.println("8 左移 2 位 = " + leftShift); System.out.println(" " + String.format("%32s", Integer.toBinaryString(leftShift)).replace(' ', '0')); // 右移 int rightShift = num1 >> 2; System.out.println("8 右移 2 位 = " + rightShift); System.out.println(" " + String.format("%32s", Integer.toBinaryString(rightShift)).replace(' ', '0')); // 负数右移 int negRightShift = num2 >> 2; System.out.println("-8 右移 2 位 = " + negRightShift); System.out.println(" " + String.format("%32s", Integer.toBinaryString(negRightShift)).replace(' ', '0')); // 无符号右移 int unsignedRightShift = num2 >>> 2; System.out.println("-8 无符号右移 2 位 = " + unsignedRightShift); System.out.println(" " + String.format("%32s", Integer.toBinaryString(unsignedRightShift)).replace(' ', '0')); } }
&位运算
位都为1,结果才为1,否则结果为0。
|位运算
位只要有一个为1,那么结果就是1,否则就为0。
^位运算
两个操作数的位中,相同则结果为0,不同则结果为1。
~位运算
如果位为0,结果是1,如果位为1,结果是0。
三目运算符
- 语法格式:
条件表达式? 表达式1 : 表达式2。- 如果条件表达式为true,则取表达式1的值,否则就取表达式2的值。
public class TernaryDemo { public static void main(String[] args) { int a = 10; int b = 20; // 使用三目运算符找出最大值 int max = (a > b) ? a : b; System.out.println("a = " + a + ", b = " + b); System.out.println("max = " + max); // 嵌套三目运算符找出最小值 int min = (a < b) ? a : (a == b ? a : b); System.out.println("min = " + min); } }
运算符优先级
- 括号
()的优先级最高,可以用来强制指定计算顺序。- 一元运算符(如
++、--、!)的优先级较高,紧接着是乘法、除法和余数运算符。- 乘法、除法 和 加法、减法 的优先级分别较低。
- 比较运算符、逻辑运算符 和 赋值运算符 的优先级逐步降低。
- 赋值运算符
=和三目运算符?:是从右到左计算的。
优先级 运算符 说明 结合性 1 ()、[]、. 方法调用、数组访问、成员访问 左到右 2 ++、— 后缀自增、自减 左到右 3 ++、—、+(一元)、-(一元)、~、! 前缀自增/自减、一元正负、按位取反、逻辑非 右到左 4 *、/、% 乘法、除法、取余 左到右 5 +、- 加法、减法(字符串拼接也使用 +) 左到右 6 <<、>>、>>> 位移运算(左移、右移、无符号右移) 左到右 7 <、<=、>、>=、instanceof 比较运算、类型检测 左到右 8 ==、!= 相等、不相等 左到右 9 & 按位与 左到右 10 ^ 按位异或 左到右 11 | 按位或 左到右 12 && 逻辑与(短路与) 左到右 13 || 逻辑或(短路或) 左到右 14 ?: 三目条件运算符 右到左 15 =、+=、-=、*=、/=、%=、&=、^=、|=、<<=、>>=、>>>= 赋值与复合赋值 右到左 16 , 逗号运算符(顺序执行多个表达式) 左到右
