专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java高级进阶-从计算机底层解析左移、右移、无符号右移

temp10 2024-10-24 17:17:46 java教程 14 ℃ 0 评论

开始之前,想必大家都很熟悉这样一道面试题:

java面试题int a=2*8怎样运算效率最快

Java高级进阶-从计算机底层解析左移、右移、无符号右移

用移位运算 int a=2<<3;

a就是2乘以8 最后结果是16 这是最省内存 最有效率的方法

解释一下:

2的二进制是10, 在32位存储器里面是0000 0000 0000 0010

左移三位后变成 0000 0000 0001 0000 也就是16

java中的位运算

首先要明白一点,这里面所有的操作都是针对存储在计算机中中二进制的操作,那么就要知道,正数在计算机中是用二进制表示的,负数在计算机中使用补码表示的。

左移位:<<,有符号的移位操作

左移操作时将运算数的二进制码整体左移指定位数,左移之后的空位用0补充

右移位:>>,有符号的移位操作

右移操作是将运算数的二进制码整体右移指定位数,右移之后的空位用符号位补充,如果是正数用0补充,负数用1补充。

扩展:

1.原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。

2.反码的表示方法是:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。

3.补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)

4.原码和反码的相互转换:符号位不变,数值位按位取反

5.原码和补码的相互转换:符号位不变,数值位按位取反,末位再加1

6.已知补码,求原码的负数的补码:符号位和数值位都取反,末位再加1

例子:

public static void main(String[] args)
{
System.out.println(3<<2);//3左移2位
System.out.println(-3<<2);//-3左移2位
System.out.println(6>>2);//6右移2位
System.out.println(-6>>2);//-6右移2位
}
输出结果
12
-12
1
-2

下面解释一下:

00000000 00000000 00000000 00000011 3在32位计算机中表示

00000000 00000000 00000000 0000001100 左移2位,补0,结果为12

----------------------------------------------------------------------------------------------

00000000 00000000 00000000 00000011 +3在在32位计算机中表示

11111111 11111111 11111111 11111100 取反码

11111111 11111111 11111111 11111101 -3在计算机中表示(反码+1)

11111111 11111111 11111111 1111110100 左移2位,补0,结果为负数,就是补码了,

10000000 00000000 00000000 00001011 求原码

10000000 00000000 00000000 00001100 结果-12

----------------------------------------------------------------------------------------------

00000000 00000000 00000000 00000110 +6在计算机中表示方法

0000000000 00000000 00000000 000001 右移两位,正数补0,结果为1

----------------------------------------------------------------------------------------------

00000000 00000000 00000000 00000110 +6在32位计算机中表示方法

11111111 11111111 11111111 11111001

11111111 11111111 11111111 11111010 -6在在32位计算机中的表示

1111111111 11111111 11111111 111110 右移两位,结果为负数

1000000000 00000000 00000000 000001

1000000000 00000000 00000000 000010 结果为-2

这个地方很容易弄混,多想几次就会慢慢理解了。

上面解释了带符号的移位操作,下面解释一下不带符号的移位操作

无符号的移位只有右移,没有左移,使用“>>>”进行移位,都补充0

例如:

public static void main(String[] args)
{
System.out.println(6>>>2);
System.out.println(-6>>>2);
}
结果:
1
1073741822

分析:

00000000 00000000 00000000 00000110 +6在计算机中表示方法

0000000000 00000000 00000000 00000110 右移两位,正数补0,结果为1

-----------------------------------------------------------------------------------------------

00000000 00000000 00000000 00000110 +6在计算机中表示方法

11111111 11111111 11111111 11111001

11111111 11111111 11111111 11111010 -6在计算机中的表示

0011111111 11111111 11111111 11111010 右移两位,补充0,结果为1073741822

补充

移位操作要注意的问题是高(低)位是补0还是补1和对char, byte, short型的操作:

(1)<< : (left-shift), 最低位补0

(2)>> : (signed right-shift), 右移过程使用符号位扩展(sign extension),即如果符号为1则高位补1, 是0则补0,也就是逻辑右移

(3)>>> : (unsigned right-shit),右移过程使用零扩展(zero extension),即最高位一律补0,也就是算术右移

(4)移位操作的数据类型可以是byte, char, short, int, long型,但是对byte, char, short进行操作时会先把它们变成一个int型,最后得到一个int型的结果,对long型操作时得到一个long型结果,不可以对boolean型进行操作。

(5)移位操作符可以和=合并起来,即 <<= 、 >>= 和 >>>=。例如 a >>= 2; 表示将a右移两位后的值重新赋给a。当时在使用这三个操作符对 byte, char, short型数据进行操作时要注意,例如有一下代码片段:

public class ShiftTest
{
public static void main(String [] args)
{
byte a;
byte b;
byte c;
a = 127;
b = 127;
c = 127;
a <<= 2;
System.out.println(a);
System.out.println(b <<= 2);
System.out.println(c << 2);
}
}
运行结果是:
-4
-4
508

这说明了在操作a <<= 2 执行过程是这样的:先将 byte型的数 127变成int型,左移2位得到 508,然后把508赋给byte型变量a时只是简单地"折断"(truncate)得到数-4。编译时编译器不会提示你可能损失精度(实际上在本例中确实是损失精度了),但是如果你把a <<= 2改成 a = a << 2;编译器就会提示可能损失精度了。

总结

移位操作的简单计算方法

>>右移操作

x>>y

就是x除以2的y此方,取最小整数

<<左移操作

X<<y

就是x乘以2的y次方

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表