Java基础概览和常用知识(五)
自增自减运算符
在写代码的过程中,常见的一种情况是需要某个整数类型变量增加 1 或减少 1。Java 提供了自增运算符 (++) 和自减运算符 (--) 来简化这种操作。
++ 和 -- 运算符可以放在变量之前,也可以放在变量之后:
- 前缀形式(例如
++a或--a):先自增/自减变量的值,然后再使用该变量,例如,b = ++a先将a增加 1,然后把增加后的值赋给b。 - 后缀形式(例如
a++或a--):先使用变量的当前值,然后再自增/自减变量的值。例如,b = a++先将a的当前值赋给b,然后再将a增加 1。
为了方便记忆,可以使用下面的口诀:符号在前就先加/减,符号在后就后加/减。
下面来看一个考察自增自减运算符的高频笔试题:执行下面的代码后,a 、b 、 c 、d和e的值是?
int a = 9;
int b = a++;
int c = ++a;
int d = c--;
int e = --d;
答案:a = 11 、b = 9 、 c = 10 、 d = 10 、 e = 10。
移位运算符
移位运算符(Shift Operators)是编程中用于对二进制位进行操作的运算符。它们主要用于对整数类型的变量进行高效的位级操作。移位就是将其向左或向右移动若干位的运算。移位运算符包括左移(<<)、右移(>>)和无符号右移(>>>)。
移位运算符在各种框架以及 JDK 自身的源码中使用还是挺广泛的,HashMap(JDK1.8) 中的 hash 方法的源码就用到了移位运算符:
左移运算符(<<)
左移运算符将操作数的二进制表示向左移动指定的位数,右边空出的位用0填充。左移一位相当于乘以2,因为每向左移动一位,二进制数的值就翻倍。
int a = 5; // 二进制表示为 0000 0101
int b = a << 2; // 左移2位,结果为 0001 0100,即十进制的20
右移运算符(>>)
右移运算符将操作数的二进制表示向右移动指定的位数,左边空出的位根据符号位(最左边的位)进行填充。对于正数,左边空出的位用0填充;对于负数,左边空出的位用1填充(这是算术右移)。
int a = 20; // 二进制表示为 0001 0100
int b = a >> 2; // 右移2位,结果为 0000 0101,即十进制的5 int c = -20; // 二进制表示为 1111 1111 1111 1111 1111 1111 1110 1100(补码表示)
int d = c >> 2; // 右移2位,结果为 1111 1111 1111 1111 1111 1111 1111 1011,即十进制的-5
无符号右移运算符(>>>)
无符号右移运算符将操作数的二进制表示向右移动指定的位数,左边空出的位总是用0填充,无论操作数的符号位如何。这种操作通常用于处理无符号整数或需要忽略符号位的场景。
int a = -20; // 二进制表示为 1111 1111 1111 1111 1111 1111 1110 1100(补码表示)
int b = a >>> 2; // 无符号右移2位,结果为 0011 1111 1111 1111 1111 1111 1111 0110,即十进制的1073741818
虽然移位运算本质上可以分为左移和右移,但在实际应用中,右移操作需要考虑符号位的处理方式。
由于 double,float 在二进制中的表现比较特殊,因此不能来进行移位操作。
移位操作符实际上支持的类型只有int和long,编译器在对short、byte、char类型进行移位前,都会将其转换为int类型再操作。
使用移位运算符的主要原因:
- 高效性:移位操作通常比乘法和除法操作更快,因为它们是直接在硬件层面实现的。
- 紧凑性:移位操作可以用于紧凑地表示和处理二进制数据,这在嵌入式系统、网络通信和低级编程中非常有用。
- 位掩码:移位操作常用于生成位掩码(bitmask),用于对特定位进行读取、设置或清除操作。
- 算法优化:某些算法(如快速傅里叶变换、位图处理等)可以通过移位操作实现高效的实现。
移位运算符最常用于快速乘以或除以 2 的幂次方。除此之外,它还在以下方面发挥着重要作用:、
- 位字段管理:例如存储和操作多个布尔值。
- 哈希算法和加密解密:通过移位和与、或等操作来混淆数据。
- 数据压缩:例如霍夫曼编码通过移位运算符可以快速处理和操作二进制数据,以生成紧凑的压缩格式。
- 数据校验:例如 CRC(循环冗余校验)通过移位和多项式除法生成和校验数据完整性。。
- 内存对齐:通过移位操作,可以轻松计算和调整数据的对齐地址。
如果移位的位数超过数值所占有的位数会怎样?
当 int 类型左移/右移位数大于等于 32 位操作时,会先求余(%)后再进行左移/右移操作。也就是说左移/右移 32 位相当于不进行移位操作(32%32=0),左移/右移 42 位相当于左移/右移 10 位(42%32=10)。当 long 类型进行左移/右移操作时,由于 long 对应的二进制是 64 位,因此求余操作的基数也变成了 64。
也就是说:x<<42等同于x<<10,x>>42等同于x>>10,x >>>42等同于x >>> 10。
左移运算符代码示例:
int i = -1;
System.out.println("初始数据:" + i);
System.out.println("初始数据对应的二进制字符串:" + Integer.toBinaryString(i));
i <<= 10;
System.out.println("左移 10 位后的数据 " + i);
System.out.println("左移 10 位后的数据对应的二进制字符 " + Integer.toBinaryString(i));
输出:
初始数据:-1
初始数据对应的二进制字符串:11111111111111111111111111111111
左移 10 位后的数据 -1024
左移 10 位后的数据对应的二进制字符 11111111111111111111110000000000
由于左移位数大于等于 32 位操作时,会先求余(%)后再进行左移操作,所以下面的代码左移 42 位相当于左移 10 位(42%32=10),输出结果和前面的代码一样。
int i = -1;
System.out.println("初始数据:" + i);
System.out.println("初始数据对应的二进制字符串:" + Integer.toBinaryString(i));
i <<= 42;
System.out.println("左移 10 位后的数据 " + i);
System.out.println("左移 10 位后的数据对应的二进制字符 " + Integer.toBinaryString(i));
右移运算符使用类似。
continue、break 和 return 的区别是什么?
在循环结构中,当循环条件不满足或者循环次数达到要求时,循环会正常结束。但是,有时候可能需要在循环的过程中,当发生了某种条件之后 ,提前终止循环,这就需要用到下面几个关键词:
continue:指跳出当前的这一次循环,继续下一次循环。break:指跳出整个循环体,继续执行循环下面的语句。
return 用于跳出所在方法,结束该方法的运行。return 一般有两种用法:
return;:直接使用 return 结束方法执行,用于没有返回值函数的方法return value;:return 一个特定值,用于有返回值函数的方法
思考一下:下列语句的运行结果是什么?
public static void main(String[] args) {boolean flag = false;for (int i = 0; i <= 3; i++) {if (i == 0) {System.out.println("0");} else if (i == 1) {System.out.println("1");continue;} else if (i == 2) {System.out.println("2");flag = true;} else if (i == 3) {System.out.println("3");break;} else if (i == 4) {System.out.println("4");}System.out.println("xixi");}if (flag) {System.out.println("haha");return;}System.out.println("heihei");
}
运行结果:
0
xixi
1
2
xixi
3
haha