什么是2进制
2进制:逢2进1的计数规律
10进制
规则:逢10进1
数字:0 1 2 3 4 5 6 7 8 9
权:万 千 百 十 个
基数:10
2进制
规则:逢2进1
数字:0 1
权:128 64 32 16 8 4 2 1
基数:2
计算机为何采用2进制:成本低!
00000000 00000000 00000000 00000000 0
00000000 00000000 00000000 00000001 1
00000000 00000000 00000000 00000010 2
00000000 00000000 00000000 00000011 3
00000000 00000000 00000000 00000100 4
00000000 00000000 00000000 00000101 5
00000000 00000000 00000000 00000110 6
00000000 00000000 00000000 00000111 7
00000000 00000000 00000000 00001000 8
00000000 00000000 00000000 00001001 9
00000000 00000000 00000000 00001010 10
00000000 00000000 00000000 00001011 11
00000000 00000000 00000000 00001100 12
00000000 00000000 00000000 00001101 13
00000000 00000000 00000000 00001110 14
00000000 00000000 00000000 00001111 15
…
00000000 00000000 00000000 00110001 =32+16+1=49(10)
00000000 00000000 00000000 01100100 =64+32+4=100(10)
2进制转换为10进制:将包含1的位置权值求和
案例:
package demo;
public class Demo01 {
public static void main(String[] args) {
/*
* 2进制
*/
int n = 50;//"50"编译后 110010,n就是2进制的!
//Integer.toBinaryString() 是Java提供的现成
//静态方法,在Integer类上定义的工具方法
//Binary: 2进制 toBinaryString:将计算机内存
//中的int类型2进制存储情况做展示
//toBinaryString 方法会自动省略高位的0
System.out.println(Integer.toBinaryString(n));
n++;
System.out.println(Integer.toBinaryString(n));
for(int i=0; i<=100; i++) {
System.out.println(Integer.toBinaryString(i));
}
//输出0~100的2进制
//从中抽取20个数,手工换算10进制数,自行验证
}
}
什么是16进制
16进制
规则:逢16进1
数字: 0 1 2 3 4 5 6 7 8 9 a b c d e f
权:4096 256 16 1
基数:16
16进制:逢16进1的计数规律,计算机行业采用16进制,对2进制进行缩写。
如何使用16进制缩写2进制:
从2进制的最低位开始, 每4位2进制,对应缩写为1位16进制数。位数不够,高位可以补0.
案例:
package demo;
public class Demo02 {
public static void main(String[] args) {
/*
* 1. Java 7 提供2进制直接量书写格式 0b 为开头
* 2进制直接量书写非常冗长繁琐
* 2. 使用16进制简写2进制, 是常用方式
* 0x 表示16进制
* 0b 表示2进制
*/
int n = 0b0011_0111_1110_0011_1111_1001_1010_0111;
// 3 7 e 3 f 9 a 7
int m = 0x37e3f9a7;
System.out.println(Integer.toBinaryString(n));
System.out.println(Integer.toBinaryString(m));
}
}
补码
补码: 计算机中处理负数的一种编码,设计目的是将固定位数2进制,分一半作为负数使用。因为其编码中正负数互补对称,故称为“补码”
补码编码分析:采用4位2进制数,
讨论补码的规律推广到32位数(int)补码
补码的编码规则:
1.采用固定位数编码,计算时候多出位数自动溢出
2.高位为0的是正数、高位为1是负数,最高位称为符号位,符号位参与计算
3.从0开始倒推负数编码
案例:
public class Demo03 {
public static void main(String[] args) {
/*
* int 类型,32位数, 的最大值,最小值编码
* int 在内存中的编码是补码!
*/
int max = Integer.MAX_VALUE; //int最大值
int min = Integer.MIN_VALUE; //int最值
System.out.println(max);
System.out.println(min);
System.out.println(Integer.toBinaryString(max));
System.out.println(Integer.toBinaryString(min));
}
}
负数的编码:
11111111111111111111111111111111 -1
11111111111111111111111111100111 =-1-8-16=-25
11111111111111111111111111101000 =-1-1-2-4-16=-24
11111111111111111111111111001101 =-1-2-16-32 =-51
经典面试题目:
如下代码输出结果是( B ):
System.out.println(~80+1);
A.-79 B.-80 C.-81 D.80
如下代码输出结果是( C ):
System.out.println(~80);
A.-79 B.-80 C.-81 D.80
如下代码输出结果是( B ):
System.out.println(~-80+1);
A.79 B.80 C.81 D.82
如下代码输出结果是( A ):
System.out.println(~-80);
A.79 B.80 C.81 D.82
2进制运算
运算符:
~取反 &与 |或
>>> 逻辑右移位
>> 数学右移位
<< 左移位
与计算 &
基本规则:逻辑乘法, 有0则0
0 & 0 -> 0
0 & 1 -> 0
1 & 0 -> 0
1 & 1 -> 1
在运算时候,将两个运算数据对齐位数,对应位计算与。
举个例子:
7 7 b c a c 3 1
n = 01110111 10111100 10101100 00110001
m = 00000000 00000000 00000000 11111111 mask 掩码
k=n&m 00000000 00000000 00000000 00110001
如上运算意义:是一种掩码(截取)计算,利用m将n的最后8位数截取保存到k中
代码:
int n = 0x77bcac31;
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));
在软件底层经常需要将int类型拆分为4个8位数(字节)
b1 b2 b3 b4
n = 01111011 11111000 01001010 10001110
b1= 00000000 00000000 00000000 01111011
b2= 00000000 00000000 00000000 11111000
b3= 00000000 00000000 00000000 01001010
b4= 00000000 00000000 00000000 10001110
逻辑右移位计算 >>>
- 运算规则:将数字整体向右移动,低位溢出, 高位补0
举个例子:
n = 01111011 11111000 01001010 10001110
m=n>>>1 001111011 11111000 01001010 1000111
k=n>>>2 0001111011 11111000 01001010 100011
g=n>>>8 00000000 01111011 11111000 01001010
b3=(n>>>8) & 0xff;
代码:
int n = 0x7bf84a8e;
int m = n>>>1;
int k = n>>>2;
int g = n>>>8;
int b1 = (n>>>24) & 0xff;
int b2 = (n>>>16) & 0xff;
int b3 = (n>>>8) & 0xff;
int b4 = n & 0xff;
//b1 b2 b4 ?
//按照2进制输出 n m k g b1 b2 b3 b4
| 或运算
0 | 0 -> 0
0 | 1 -> 1
1 | 0 -> 1
1 | 1 -> 1
计算时候将两个数字对齐位数,对应的位置进行与计算
举个例子:
n = 00000000 00000000 10111011 00000000
m = 00000000 00000000 00000000 10111101
k=n|m 00000000 00000000 10111011 10111101
上述案例的意义:将n和m拼接为一个16位数
代码验证:
int n = 0xbb00;
int m = 0xbd;
int k = n | m;
//检验结果:按照2进制输出 n m k
左移位计算 <<
2进制数字整体向左移动,高位自动溢出,低位补0, 注意
可能会发生符号位溢出。
举个例子:
n = 00100110 11100000 10101001 01010110
m=n<<1 0100110 11100000 10101001 010101100
k=n<<2 100110 11100000 10101001 0101011000
g=n<<8 11100000 10101001 01010110 00000000
验算代码:
int n = 0x26e0a956;
int m = n<<1;
int k = n<<2;
int g = n<<8;
//按照2进制输出 n m k g
将4个字节(8位、Byte)合并为一个int
b1= 00000000 00000000 00000000 01111011
b2= 00000000 00000000 00000000 11111000
b3= 00000000 00000000 00000000 01001010
b4= 00000000 00000000 00000000 10001110
b1<<24 01111011 00000000 00000000 00000000
b2<<16 00000000 11111000 00000000 00000000
b3<<8 00000000 00000000 01001010 00000000
b4= 00000000 00000000 00000000 10001110
n = (b1<<24)|(b2<<16)|(b3<<8)|(b4)
b1 b2 b3 b4
n = 01111011 11111000 01001010 10001110