文章目录
二进制
1.1 什么是2进制
逢2进1的计数规则
public class Demo02 {
public static void main(String[] args) {
/*
* Java 在编译阶段, 将10进制字面量都
* 编译为2进制数
* Integer.toBinaryString(n) 将n按照
* 内存实际存储的情况,输出,
* 输出时候高位0省略
*/
int n = 666; //n = 666
System.out.println(Integer.toBinaryString(n));
System.out.println(n); //1010011010->"666"
}
}
1.2 什么是16进制
逢16进1的计数规则, 在计算机编程中, 采用16进制简写2进制。
由于16进制的基数16是2进制基数2的4次方,所以,可以每4个2进制数缩写为1位16进制。
public class Demo03 {
public static void main(String[] args) {
/*
* 2进制书写繁琐
* Java 7 开始提供了2进制直接量前缀0b
* 使用下划线分隔,不影响数值
* 采用16进制缩写
*/
int n = 0b10_1101_1001; //1+8+16+64+128+512
System.out.println(n);
n = 0b1011_1110_1001_1111_1000_1010_1010;
System.out.println(Integer.toBinaryString(n));
n = 0xbe9f8aa;
System.out.println(Integer.toBinaryString(n));
}
}
1.3 补码
计算机中用于处理负数的编码, 编码思路将固定位数的2进制,分一半作为负数使用。
高位为1 的作为负数, 高位为0的作为正数, 最高位称为符号位, 注意符号位参与运算。
采用4位2进制数,设计为补码, 讨论编码方式, 规定: 计算时候保持4位数,多于的位数自动移除。
package binary;
public class Demo04 {
public static void main(String[] args) {
/*
* int 类型的编码
*/
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));
int n = -1;
System.out.println(Integer.toBinaryString(n));
n = -3;
System.out.println(Integer.toBinaryString(n));
n = -28;
System.out.println(Integer.toBinaryString(n));
}
}
正数的规律: 2进制转换为10机制
00000000000000000000000000000000 = 0
00000000000000000000000000011011 = 1+2+8+16 = 27
负数的规律:负数补码转换为10进制。
11111111111111111111111111111111 = -1
11111111111111111111111111111101 = -1-2 = -3
11111111111111111111111111111100 = -1-1-2 = -4
11111111111111111111111111100100 = -1-1-2-8-16 = -28
互补对称性质!这个是巧合, 在进行编码时候,完成的方案存在对称性质: -n = ~n+1
package binary;
public class Demo05 {
public static void main(String[] args) {
/*
* 补码对称
*/
int n = 56;
int m = ~n + 1;
System.out.println(m); //-56
System.out.println(~56);//-57
//运算过程分析
System.out.println(Integer.toBinaryString(n));
System.out.println(Integer.toBinaryString(~n));
System.out.println(Integer.toBinaryString(~n+1));
//注意:最小值,不能取相反数!
int min = Integer.MIN_VALUE;
int k = -min;
System.out.println(k);
}
}
原理:
00000000000000000000000000111000 = 8+16+32 = 56
11111111111111111111111111000111 = -1-8-16-32 = -57
11111111111111111111111111001000 = -1-1-2-4-16-32 = -56
1.4 二进制运算
运算符号:
& 与
| 或
~ 反
<< 左移位
>>> 逻辑右移位
>> 数学右移位
(1) 与 &
逻辑乘法, 有0则0
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1
运算时候, 将两个2进制数,对其位, 对应的位进行与运算
n = 01011101 01110110 11001110 00101101
m = 00000000 00000000 00000000 11111111
k = n & m 00000000 00000000 00000000 00101101
经典运算:掩码运算, 将一个2进制数字后n位截取下来的运算
- 将数据进行拆分
- 获取除以2的n次方的余数
00000000 00000000 00000000 00101101 = 1+4+8+32 = 45
45%8=5
00000000 00000000 00000000 00000101 = 1+4= 5
00000000 00000000 00000000 00101100 = 4+8+32 = 44
44%8=4
00000000 00000000 00000000 00000100 = 4
5 d 7 6 c e 2 d
n = 01011101 01110110 11001110 00101101
n % 8
n & 0x7
案例:
int n = 0x5d78ce2d;
int m = 0xff;
int k = n & m;
System.out.println(Integer.toBinaryString(n));
System.out.println(Integer.toBinaryString(m));
System.out.println(Integer.toBinaryString(k));
System.out.println(n % 8);
System.out.println(n & 0x7);
System.out.println(n % 16);
System.out.println(n & 0xf);
(2) 右移位运算 >>>
将2进制数字的整体向右移动,低位自动溢出,高位补0
2 e b 7 3 7 3 7
n = 00101110 10110111 00110111 00110111
m = n>>>1 000101110 10110111 00110111 0011011
k = n>>>2 0000101110 10110111 00110111 001101
g = n>>>8 00000000 00101110 10110111 00110111
代码:
int n = 0x2eb73737;
int m = n>>>1;
int k = n>>>2;
int g = n>>>8;
https://gitee.com/robin_home/binary2209.git
案例:将一个int类型数据拆分为4个字节
例子:
b1 b2 b3 b4
n = 00101110 10110111 00110111 00110111
b1 = 00000000 00000000 00000000 00101110
b2 = 00000000 00000000 00000000 10110111
b3 = 00000000 00000000 00000000 00110111
b4 = 00000000 00000000 00000000 00110111
b4 = n & 0xff;
b3 = (n>>>8) & 0xff;
b2 = (n>>>16) & 0xff;
b1 = (n>>>24) & 0xff;
代码:
int n = 0x2eb73737;
int b4 = n & 0xff;
int b3 = (n>>>8) & 0xff;
int b2 = (n>>>16) & 0xff;
int b1 = (n>>>24) & 0xff;
(3) 或 |
运算规则:逻辑加法,有1则1
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
运算时候, 对齐位, 对应位计算
n 00000000 00000000 00000000 10111011
m 00000000 00000000 10111110 00000000
k =n|m 00000000 00000000 10111110 10111011
如上案例的意义:错位合并
int n = 0xbb;
int m = 0xbe00;
int k = m | n;
(4) 左移位运算
规则:2进制数字整体向左移动, 高位自动溢出, 低位自动补0
n 01011101 10010011 10111000 00111011
m = n<<1 1011101 10010011 10111000 001110110
k = n<<2 011101 10010011 10111000 0011101100
b2 = 00000000 00000000 00000000 10110111
b2<<8 00000000 00000000 10110111 00000000
int n = 0x5d93b83b;
int m = n<<1;
int k = n<<2;
int b2 = 0xb7;
System.out.println(Integer.toBinaryString(b2<<8));
将4个字节拼接为一个int(错位合并)
b1 = 00000000 00000000 00000000 00101110
b2 = 00000000 00000000 00000000 10110111
b3 = 00000000 00000000 00000000 00110111
b4 = 00000000 00000000 00000000 00110111
b1 << 24 00101110 00000000 00000000 00000000
b2 << 16 00000000 10110111 00000000 00000000
b3 << 8 00000000 00000000 00110111 00000000
b4 << 0 00000000 00000000 00000000 00110111
n = (b1<<24) | (b2<<16) | (b3<<8) | (b4<<0)
int b1 = 0x2e;
int b2 = 0xb7;
int b3 = 0x37;
int b4 = 0x37;
int n = (b1<<24) | (b2<<16) | (b3<<8) | (b4<<0);
1.5 int 序列化
将一个int转换为byte数组, 是序列化
将一个字节数组转换为int数据,是反序列化
封装成方法
public class Demo10 {
public static void main(String[] args) {
int n = 0x6a7b9cef;
System.out.println(Integer.toBinaryString(n));
byte[] bytes = toBytes(n);
System.out.println(Integer.toBinaryString(bytes[0] & 0xff));
System.out.println(Integer.toBinaryString(bytes[1] & 0xff));
System.out.println(Integer.toBinaryString(bytes[2] & 0xff));
System.out.println(Integer.toBinaryString(bytes[3] & 0xff));
int m = toInt(bytes);
System.out.println(Integer.toBinaryString(m));
}
public static byte[] toBytes(int n){
int b1 = (n >>> 24) & 0xff;
int b2 = (n >>> 16) & 0xff;
int b3 = (n >>> 8) & 0xff;
int b4 = (n >>> 0) & 0xff;
return new byte[]{(byte)b1, (byte)b2, (byte)b3, (byte)b4};
}
public static int toInt(byte[] bytes){
int b1 = bytes[0] & 0xff; // 10111011
int b2 = bytes[1] & 0xff;
int b3 = bytes[2] & 0xff;
int b4 = bytes[3] & 0xff;
return (b1<<24) | (b2<<16) | (b3<<8) | (b4<<0);
}
}
(1) 符号位扩展现象:
int n = -1
// 11111111 11111111 11111111 11111111
long l = n;
// 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111
n = -3;
// 11111111 11111111 11111111 11111101
l = n;
// 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111101
n = 3;
// 00000000 00000000 00000000 00000011
l = n;
// 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000011
byte 11111101
int 11111111111111111111111111111101
0xff 00000000000000000000000011111111
b & 0xff 00000000000000000000000011111101
public class Demo09 {
public static void main(String[] args) {
byte b = -3; //11111101
//符号位扩展:负数时候 byte 转换为 int 高位补充24个1
System.out.println(Integer.toBinaryString(b));
//消除符号位扩展:利用掩码计算,消除高位1
System.out.println(Integer.toBinaryString(b & 0xff));
}
}
(2) 移位运算的数学意义
左移位一次,相当于数学乘以2
右移位一次,相当于数学除以2
(3) >>
数学右移位 和 >>>
逻辑右移位的区别
>>
正数时候, 高位补0; 负数时候,高位补1
>>>
无论正负高位补0, 不考虑数学结果,数字逻辑上向右移动
例子:
n 11111111 11111111 11111111 11011000 = -1-1-2-4-32 = -40
m = n>>1 111111111 11111111 11111111 1101100 = -1-1-2-16 = -20
k = n>>2 1111111111 11111111 11111111 110110 = -1-1-8 = -10
g = n>>3 11111111111 11111111 11111111 11011 = -5
h = n>>4 111111111111 11111111 11111111 1101 = -3
x = n>>>1 011111111 11111111 11111111 1101100 = max-1-2-16
public class Demo11 {
public static void main(String[] args) {
System.out.println(20); //20
System.out.println(20<<1); //40
System.out.println(20<<2); //80
System.out.println(20<<3); //160
}
}
public class Demo12 {
public static void main(String[] args) {
int n = -40;
System.out.println(Integer.toBinaryString(n));
System.out.println(Integer.toBinaryString(n>>1));
System.out.println(n>>1);
System.out.println(Integer.toBinaryString(n>>2));
System.out.println(n>>2);
System.out.println(Integer.toBinaryString(n>>3));
System.out.println(n>>3);
System.out.println(Integer.toBinaryString(n>>4));
System.out.println(n>>4);
System.out.println(Integer.toBinaryString(n>>5));
System.out.println(n>>5);
System.out.println(Integer.toBinaryString(n>>>1));
System.out.println(n>>>1);
//ArrayList 扩容1.5倍
//StringBuilder 扩容 1倍+2
}
}