6、Java 运算符
运算符是一种特殊的符号,用于表示数据的运算、赋值和比较等。
Java 语言使用功能运算符讲一个或多个操作数链接成直线性语句,用于实现特定功能。
Java 语言中运算符分为如下几种:
- 算术运算符
- 赋值运算符
- 比较运算符
- 位运算符
- 类型相关运算符(比较、逻辑、三目)
6.1 算术运算符
Java 支持所有的基本算术运算符,这些算术运算符用于执行基本的数学运算:加、减、乘、除和求余等。
下面来看看 7 个基本算术运算符。
+:加法运算符。
double a = 5.0; double b = 3.8; double sum = a + b; // sum = 8.8 System.out.println(sum);
除此之外,+ 还可以作为字符串的连接运算符。
-:减法运算符。
double a = 5.0; double b = 3.8; double sub = a - b; // sub = 1.2 System.out.println(sub);
*:乘法运算符。
double a = 5.0; double b = 4.0; double m = a * b; // m = 20.0 System.out.println(m);
/:除法运算符。
当运算符操作的两个数都是整数类型,计算结果为整数(截取整数部分);如果运算符操作的两个数中有一个或者两个都是浮点数,计算结果则就是自然运算出来的结果,不会截取掉小数部分。
public class OperatorTest { public static void main(String[] args) { int a = 3; int b = 2; // 1 System.out.println(a / b); double d = 9.5; int c = 3; // 3.1666666666666665 System.out.println(d / c); // 正无穷大 System.out.println(5 / 0.0); // 负无穷大 System.out.println(-5 / 0.0); // 错误:/ byte zero System.out.println(5 / 0); } }
%:求余运算符。
求余运算符的计算结果是第一个操作数除以第二个操作数,得到一个整除的结果后剩下的值就是余数,它的结果也不总是整数。
public class OperatorTest { public static void main(String[] args) { int a = 5; int b = 2; // 整数 1(余数) System.out.println(a % b); double c = 2.0; // 浮点数 1.0 System.out.println(a % c); // 输出非数:NaN System.out.println(5.0 % 0); System.out.println(5 % 0.0); System.out.println(0 % 0.0); // 0.0 System.out.println(0 % 5.0); // 报错:/ by zero System.out.println(5 % 0); } }
++:自加。
这是单目运算符,运算符既可以出现在操作数的左边,也可以出现在操作数的右边。
左边相当于,先给数字 + 1 然后再运算;右边相当于,先运算,然后再 + 1。
int a = 3; int b = 5; int c = a++ + b; // c = 8,a++ + b 相当于 c = a + b ; a = a + 1 System.out.println(c); // a = 4 System.out.println(a); a = 3; int d = ++a + b; // d = 9, ++a + b 相当于 a = a + 1 ; c = a + b; System.out.println(d); // a = 4 System.out.println(a);
–:自减。
和 ++ 一样也是单目运算符,是不是不是 + 1 而是 -1。
6.2 赋值运算符
赋值运算符用于为变量制定变量值,上面的所有代码都是用 = 进行赋值。
除了上面的赋值操作外,Java 赋值运算符还支持如下操作。
int f = a = b = c = d;
虽然 Java 支持这种一次为多个变量赋值的写法,但可读性不好,不建议这样做。
6.3 位运算符
Java 支持的位运算符有如下 7 个。
(&):按位与。
(|):按位或。
(~):按位非。
(^):按位异或。
(<<):左移运算符。
(>>):右移运算符。
(>>>):无符号右移运算符。
按位与、按位或、按位异或运算法则如下:
第一个运算符 | 第而个运算符 | 按位与 | 按位或 | 按位异或 |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
按位非只需要一个操作数,这个运算符将把操作数在计算机底层的二进制码按位取反。
看如下代码。
// 16 System.out.println( 88 & 21); // 7 System.out.println( 4 | 3);
88 的二进制码是 000000000000000000000001011000 而 21 的二进制码是 000000000000000000000000000010101 运算方式如图。
左移运算符是将运算符的二进制码整体左移指定位数,左移后右边空出来的位以 0 填充,示例如下。
// 352 System.out.println( 88 << 2);
运算图。
计算左移右移还可以使用如下方式:
左乘、右移
意思是左移几位就操作数乘于 2 的几次方、反之就除于 2 的几次方。例如,88 << 2 = 88 * 2 ^ 2 = 88 * 4 = 352、8 >> 2 = 8 / 2 ^ 2 = 8 / 4 = 2。
位移运算符并不适合所有的数值类型,他们只适合对 byte 、short 、char 、int 和 long 等整数类型进行运算。除此之外,进行位移运算时还需要遵循如下规则。
对于低于 int 类型(byte、short 和 char )的操作数总是先自动类型转换为 int 类型后再移位。
对于 int 类型的整数移位 a >> b,当 b >> 32 时,系统先用 b 对 32 求余(因为 int 类型只有 32 位),得到的结果才是真正移位的位数。例如,a >> 33 和 a >> 1 的结果完全一样,而 a >> 32 的结果和 a 相同。
对于 long 类型的整数移位 a >> b,当 b > 64 时,总是先用 b 对 64 求余(因为 long 类型是 64 位),得到的结果才是真正移位的位数。
6.4 比较运算符
比较运算符用于判断两个变量或常量的大小,比较的结果是一个布尔值(true 或 false)。
Java 支持的比较运算符如下:
大于( > ):只支持左右两边操作数是数字类型,如果前面变量的值大于后面,返回 true。
大于等于( >= ):只支持左右两边操作数是数字类型,如果前面变量的值大于等于后面,返回 true。
小于( < ):只支持左右两边操作数是数字类型,如果前面变量的值小于后面,返回 true。
小于等于( <= ):只支持左右两边操作数是数字类型,如果前面变量的值小于等于后面,返回 true。
等于( == ):如果比较的两个操作数都是数值类型,即使它们的数据类型不相同,只要它们的值相等,也都返回 true 。例如 97 == ‘a’ 返回 true,5.0 == 5 也返回 true。如果两个操作数比较的是引用类型,那么只有当两个引用变量引用相同的实例时才可以比较,而且这两个引用必须指向同一个对象才会返回 true。
不等于( != ):如果比较的两个操作数都是数值类型,无论他们的数据类型是否相同,只要他们的值不相等,也都返回 true。如果两个操作数都是引用类型,只有当两个引用变量引用相同的类型实例时才可以比较,只要两个引用指向的不是同一个对象就会返回 true。
public class CompareTest { public static void main(String[] args) { // true System.out.println("5.0 是否大于 4.5:" + (5.0 > 4.5)); // true System.out.println("5.0 是否等于 5:" + (5.0 == 5)); // true System.out.println("97 是否等于 A:" + (97 == 'a')); // false System.out.println("true 是否等于 false:" + (true == false)); CompareTest c1 = new CompareTest(); CompareTest c2 = new CompareTest(); // false System.out.println("c1 是否等于 c2:" + (c1 == c2)); CompareTest c3 = c1; // true System.out.println("c3 是否等于 c1:" + (c1 == c3)); } }
6.5 逻辑运算符
逻辑运算符用于操作两个布尔类型的变量或者常量,逻辑运算符主要有如下 6 个。
- 与( $$ ):前后两个操作数必须都是 true 才返回 true,否则返回 false。
- 不短路与( & ):和 && 作用相同,但不会发生短路。
- 或( || ):只要两个数中有一个是 true,就可以返回 true,否则返回 false。
- 不短路或( | ):和 || 作用相同,但不会发生短路。
- 非( ! ):只需要一个操作数,如果操作数为 true ,则返回 false;如果操作数为 false,则返回 true。
- 异或( ^ ):当两个操作数不同是才返回 true,如果两个操作数相同则返回 false。
public class LogicTest { public static void main(String[] args) { int a = 5; int b = 11; // false System.out.println((a == b && a == 4)); // false,发生短路 System.out.println((a == b && a-- == 4)); // a = 5 System.out.println(a); // false,没有发生短路 System.out.println((b == 11 && a-- == 6)); // a = 4 System.out.println(a); a = 5; b = 11; // false 不发生短路 System.out.println((a == b & a-- == 4)); // 4 System.out.println(a); // false System.out.println(!true); } }
短路分两种情况。
&& 短路,当运算符左边的操作数是 false 时,发生短路,不会执行右边的判断逻辑。
|| 短路,当运算符左边操作数是 true 是,发生短路,不会执行右边的判断逻辑。
6.6 三目运算符
三目运算符只有一个:?,格式如下
表达式 ?结果1 : 结果2
如果表达式为 true 则结果就是结果1,反之就是结果2,代码如下。
int a = 4; // a 不等于 5 System.out.println(a == 5 ? "a 等于 5" : "a 不等于 5");
6.7 运算符的结合性和优先级
Java 语言中大部分运算符只从左向右结合的,只有单目运算符、赋值运算符和三目运算符例外,其中,单目运算符、赋值运算符和三目运算符是从右向左结合的,也就是从右向左运算。
乘法和加法是两个可结合的运算,也就是说,这两个运算符左右两边的操作数可以互换位置而不会影响结果。
运算符有不同的优先级,即在表达式中的运算顺序。
运算符优先级如下表,优先级由上到下递减。
根据表中的优先级,我们分析一段代码。
int a = 4; int b = a + 2 * a;
程序先执行 2 * a 的到 6,在执行 a + 6 得到 9。
当然上面的程序是非常简单的,但是有些面试题难度可不止这点,例如:
int a = 5; int b = 4; int c = a++ - --b * ++a / b-- >> 2 % a--; // -1 System.out.println(c);
c 的值是多少?
看到这样的语句幸好是只出现在面试题中,要是谁代码中这样写,那我就要抓毛了。
因此,编写表达式时:
不要把一个表达式写的过于复杂,如果表达式过于发杂,那先分成几步来完成
不要过多的依赖运算符的优先级来控制表达式的执行顺序,可读性非常差,尽量使用()来控制执行顺序。
好了,今天的内容到这里就结束了,关注我,我们下期见