二进制

进制转换器:

Integer.parseInt(a, "2");  // 2进制
Integer.parseInt(a, "8");  // 8进制

1. 什么是二进制

java 二进制权限 java的二进制_16进制

1.1 10进制

规律:逢10进1

数字:0 1 2 3 4 5 6 7 8 9

权(weight):个 十 百 千 万

基数(base):10

1.2 2进制

规律:逢2进1

数字:0 1

权(weight):32 16 8 4 2 1

基数(base):2

注意进位与退位

六个0的位分别是

32 16 8 4 2 1

0 :000000 --> 0

1 :000001 --> 1

2 :000010 --> 2

3 :000011

4 :000100

5 :000101

6 :000110

7 :000111

8 :001000

··············

43 : 101011 --> 32+0+8+0+2+1 = 43

后面的计算同理通过每个位代表的权来算

88 :000001 011000 --> 64+16+8 = 88

93 :000001 011101 --> 64+16+8+4+1 = 93

666 :001010 011010 --> 2+8+16+128+512 = 666

781 :001100 001101 --> 1+4+8+256+512 = 781

//java1.7以后支持直接书写2进制
//0b开头2进制,0d开头10进制,0o开头8进制,0x开头16进制
int n = 0b110010;
System.out.println(n);

java 二进制权限 java的二进制_java基础篇_02

2. 16进制

2进制书写冗长、麻烦、易错

16进制用于简写(缩写)2进制

16进制的基数是2进制的整次幂(16 = 2**4),所以4位2进制可以缩写成为一个16进制数

将二进制从后向前(从低位到高位)每4位数缩写成一个16进制

2进制 16进制

0:0000 0

1:0001 1

2:0010 2

3:0011 3

4:0100 4

5:0101 5

6:0110 6

7:0111 7

8:1000 8

9:1001 9

10:1010 a

11:1011 b

12:1100 c

13:1101 d

14:1110 e

15:1111 f

2进制:0111 0111 1010 0110 0101 1111 1010 1000

16进制: 7 7 a 6 5 f a 8

每四位对应一个16进制数

工作中二进制一般写为16进制

练习

十进制:5853

二进制:0001 0110 1101 1101

16进制: 1 6 d d

java 二进制权限 java的二进制_java 二进制权限_03

3. 补码

计算机中解决负数(有符号数)问题的编码

其核心目的,是将固定位数的二进制数,分一半作为负数

补码是如何将固定位数的2进制作为负数的?

以4位二进制为例讲解补码编码规则

计算时,超过4位数时候会自动溢出舍弃,保持数字始终是4位二进制数

java 二进制权限 java的二进制_16进制_04

int型是32位补码

一半(最高位为1的数)为负数,一半(最高位为0的数)为正数

-1为:11111111111111111111111111111111 32个1

计算二进制时记得权重和-1

//补码
		//int型是32位补码
		//一半(最高位为1的数)为负数,一半(最高位为0的数)为正数
		int max = Integer.MAX_VALUE;
		int min = Integer.MIN_VALUE;
		System.out.println(max);
		System.out.println(Integer.toBinaryString(max));
		System.out.println(min);
		System.out.println(Integer.toBinaryString(min));
		//超过了会溢出贯穿,类似于一个圆,回到另外一边,最大值+1得最小值
		int max1 = Integer.MAX_VALUE+1;
		System.out.println(max1);
		System.out.println(Integer.toBinaryString(max1));
		
		int n = -1;
		int n1 = 0b11111111111111111111111111111111;//32个1
		int n2 = 0xffffffff;
		System.out.println(n);
		System.out.println(Integer.toBinaryString(n));
		System.out.println(n1);
		System.out.println(Integer.toBinaryString(n1));
		System.out.println(n2);
		System.out.println(Integer.toBinaryString(n2));

补码是环形编码

面试题常考

正数溢出得负数,负数溢出得正数,说法不全对,如果正数溢出的超过了一半,他就又是正数了

溢出的范围越大围着数的圈跑的越多,溢出结果可能是负数也可能是正数,依据具体的溢出数来判断

如下可证明

int k = 100;
		System.out.println(k+Integer.MAX_VALUE);//溢出为负数
		System.out.println(k+Integer.MAX_VALUE+Integer.MAX_VALUE);//溢出为正数

补码的互补对称性

编码结果的巧合

//互补对称
		int n = 3;
		int n1 = ~3;
		System.out.println(n1);
		System.out.println(Integer.toBinaryString(n));
		System.out.println(Integer.toBinaryString(n1));

输出结果

-4
00000000000000000000000000000011
11111111111111111111111111111100

3与-4互补对称

根据这个我们可以推出下式(互补对称现象)

-n = ~n+1 ~取反符

一个数的负数等于这个数取反+1(最小值除外)

//验证互补对称公式
        int n = 3;
		if(-n == ~n+1){
			System.out.println("true");
		}
		//最小值不符合,最小值取反+1还是最小值本身
		int m = Integer.MIN_VALUE;
		int m1 = ~m+1;
		System.out.println(m);
		System.out.println(m1);

经典面试题

System.out.println(~5);
        //如上代码的输出结果为(D)A.5 B.6 C.-5 D.-6 
		System.out.println(~-5);
        //如上代码的输出结果为(A)A.4 B.5 C.6 D.7

4. 二进制运算

正数计算逢1加该位上的权重,最后加0

负数计算逢0减该位上的权重,最后加-1

运算符号

~ 取反 & 与 | 或 >> 右移位 >>>右逻辑移位 <<左移位

  1. & 与计算(逻辑乘法)

基本规则 0&0=0 0&1=0 1&0=0 1&1=1 (有0则为0)

计算时需要将两个数字对其位数,对应位置的数字计算与运算

举个例子

n = 01101111 11110000 01101100 10011010

m= 00000000 00000000 00000000 11111111 //掩码

n&m = 00000000 00000000 00000000 10011010

如上计算意义:n&m 是n 的最后8位(掩码计算,也叫拆分计算),8位为1字节,互联网传送的就是一字节为单位

用于互联网信息传输,通过掩码来将信息拆分成字节

**8位掩码(Mask):**1的个数有8个 00000000 00000000 00000000 11111111

int n = 0x7754bff7;
		int m = 0xff; //8为掩码(Mask):1的个数有8个
		int k = n&m;
		System.out.println(Integer.toBinaryString(n));
		System.out.println(Integer.toBinaryString(k));
  1. ">>>" 逻辑右移位计算

[外链图片转存失败(img-CjPApQua-1563964689056)(C:\Users\Tedu\AppData\Roaming\Typora\typora-user-images\1563870055750.png)]

“k>>>n” 把k向右移位n次,多余的不要

int n = 0x7754bff7;
		int n1 = n>>>8; //把n右移位8次
		int m = 0xff; //8为掩码(Mask):1的个数有8个
		int k = n1&m;
		System.out.println(Integer.toBinaryString(n));
		System.out.println(Integer.toBinaryString(k));

通过与计算和移位计算可以把int拆分为字节型

public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入一个数:");
		int n = input.nextInt();
		int m = 0xff;
        //System.out.println(Integer.toBinaryString(n));
		for(int i=0;i<4;i++){
		    System.out.print("从右到左第"+(i+1)+"个8位字节存的值:");
			System.out.println(Integer.toBinaryString(n>>>(i*8)&m));
		}
	}
  1. | 或运算(逻辑加法)

基本规则:有1得1

0|0=0 0|1=1 1|0=1 1|1=1

计算时,将两个数的数位对齐,对应的位数进行或计算

举个例子:

n = 00000000 00000000 00000000 10011101

m = 00000000 00000000 11011111 00000000

n|m = 00000000 00000000 11011111 10011101

如上计算意义:将n和m两个数字进行拼接计算

public static void main(String[] args) {
		//或运算
		int n = 0x9d;
		int m = 0xdf00;
		int k = n|m; //拼接
		System.out.println(Integer.toBinaryString(n));
		System.out.println(Integer.toBinaryString(m));
		System.out.println(Integer.toBinaryString(k));
	}
  1. << 左移位

将2进制数字每个位 向左移动,高位溢出,低位补0

综合应用起来的代码:

public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		System.out.println("请输入一个数:");
		int n = input.nextInt();
		int[] arr = new int[4];//定义一个接收拆分为字节的数组
		int n1=0;  //定义一个接收合并数的变量
		int m = 0xff; //定义8位掩码
		//输出显示输入数的二进制
		System.out.println("该数的二进制为:"+Integer.toBinaryString(n));
		//对该数进行拆分
		for(int i=0;i<4;i++){
			arr[i] = n>>>(i*8)&m;
		    System.out.print("从右到左第"+(i+1)+"个8位字节存的值:");
			System.out.println(Integer.toBinaryString(arr[i]));
		}
		//对该数进行合并
		for(int i=0;i<4;i++){
			n1 += arr[i]<<(8*i);  
		}
		//输出合并后的数
		System.out.println("合并后为:"+Integer.toBinaryString(n1));
	}

java 二进制权限 java的二进制_System_05

移位计算的数学意义

10进制时候,数字向左移动1次,数值扩大10倍

发现,移动改变的值与权有关

50: 110010.

100: 1100100.

二进制的时候,数字向左移动一次,数值扩大2倍

50: 110010.

25: 11001.

12: 1100. //向小方向取整

二进制的时候,数字向右移动一次,数值缩小两倍,超过的舍弃,小方向取整

">>“与”>>>"的区别:

">>"称为数学右移位计算,当正数时候(高位为0),高位补0;当负数的时候(高位为1),高位补1。其运算结果是数学除法,向小方向取整。

">>>"称为逻辑右移位计算,无论正负高位都补0,负数时候不符合数学运算结果

举个例子;

n = 11111111 11111111 11111111 11001110 // -50

n>>1 = 11111111 11111111 11111111 11100111 // -25

n>>2 = 11111111 11111111 11111111 11110011 // -13

n>>>1 = 01111111 11111111 11111111 11100111 // 比最大值小24

得到结论:

“>>”更接近数学结果:除以2,向小方向取整

">>>"单纯将数位向右移动,其结果不考虑数学意义,进行数字拆分合并时候采取纯正的向右移动

面试案例:

替代2的整数倍乘法时,采用数学移位

n * 32可以替换为 ( n<<5 ) //32为2的5次方

n / 2 (n>=0) 可以替换为 ( n>>1 )