Bootstrap

二进制、十进制、十六进制理解

目录:

1.如何理解二进制、十进制、十六进制

2.Java中实现二进制、十进制、十六进制转换

3.Java &、&&、|、||、^、<<、>>、~、>>>等运算符

4.int & 0xFF的含义

5.为什么java中中文转byte字节数组出现负数


1.如何理解二进制、十进制、十六进制

点击查看原文

1.1 十进制的理解:

生活中我们遇到的绝大部分数据都是十进制的,比如7、24、30、365等,如果把它们按照个位、十位、百位分解,可以这样表示:

数值

个位

十位

百位

7

7

0

0

24

4

2

0

30

0

3

0

365

5

6

3

把表格中的数值,用数学运算表达式表示是这样的:

数值

分解

7

1*7

24

10*2+1*4

30

10*3+1*0

365

100*3+10*6+1*5

十进制是“逢十进一”的规则,例如数字9,已经是个位上能够表示的最大的数值了,如果要表示更大的数值,就需要突破个位,使用十位来组成一个“数字串”来表示了,比如10(十位上是1,个位上是0),因此对十进制的的加法可以这样理解:

例如:8+7=15

  1. =8+(2+5)
  2. =8+2+5
  3. =10+5
  4. =15

1.2二进制的理解

二进制是“逢二进一”,也就是说二进制只有0、1两个数字来表示,遇到2时就需要向高位“进一”了,比如“24”使用二进制来表示就是“0001 1000”

如果在书写或者程序中使用这样的表示方式,就太啰嗦了,且不便于 其他进制区分,所以有了一个来表示二进制的规定,就是0b(十六进制是0x来表示),比如刚才的“0000 0000 0001 1000”可以使用“0b00011000”。

在十进制中像365这样的数值,我们可以这样理解:

  1. 365=100*3+10*6+1*5

相应的在二进制中也有类似的规则,区别是:

十进制是“逢十进一”,采用“个/十/百/千/......”的进位递增;

二进制是“逢二进一”,采用“1/2/4/8/16/......”的进位递增

下面以几个二进制数值来举例:


把上面表格的表达方式用数学运算表达式表示的话,是这样的:

其实根本就在于,十进制中相邻进制之间相差10倍,而二进制中相邻进制之间相差的是2倍,只要记住这点,然后使用十进制相似的规则去套就行了。

1.3十六进制的理解

在理解二进制的基础上来理解十六进制,只需要转换一些概念就行。

十六进制是使用16个“数字”来表示的,由于0~9只有10个数字,因此就制定了A、B、C、D、E、F六个字母来表示剩余的几个数字,分别是10、11、12、13、14、15。

简单来说,就是把四个二进制“数字”为一组,合起来用一个“十六进制”里的“数字”来表达。

二进制的表达使用的是0b,十六进制的表达使用的是0x

我们按照前边的十进制和二进制的方式来举例几个十六进制的数值:

上面表格的表达方式用数学运算表达式表示的话,就是下面这样:

请留意:0xA等于10,0xF等于15

在二进制和十进制中,相邻进制之间相差的倍数分别为2倍和10倍,而在十六进制中从上表可以看出相邻进制之间相差倍数为16倍,也就是:

“逢十六进一”,采用“1/16/256/4096/......”的进位递增。

1.4补充信息

针对上面的描述,补充一些信息:

  1. 书写二进制数值时,为了工整一般会补足四位

例如:“0b110”一般写作“0b0110”

  1. 书写十六进制数值时,为了工整一般会补足两位或者四位

例如:0x06(补足为两位),0x01FF(补足为四位)

2.Java中实现二进制、十进制、十六进制转换

Java中的Integer类提供了将int转为二进制、八进制、十进制、十六进制的方法,分别是:

FormToMethod
十进制十六进制Integer.toHexString(int i)

十进制

八进制Integer.toOctalString(int i)
十进制二进制Integer.toBinaryString(int i)
十六进制十进制Integer.valueOf("FFFF",16).toString()
八进制十进制Integer.valueOf("876",8).toString()
二进制十进制Integer.valueOf("0101",2).toString()

通过Integer.parseInt()方法可直接将二进制、八进制、十六进制转为十进制

parseInt(String s, int radix)

使用第二个参数指定的基数,将字符串参数解析为有符号的整数。

3.Java &、&&、|、||、^、<<、>>、~、>>>等运算符

点击查看原文

java运算大致分为逻辑运算符、算数运算符、位运算符和其他运算符:

  • 逻辑运算符:&&、||、!
  • 算数运算符:+、-、*、/、+=
  • 位运算符:^、|、&
  • 其他运算符:三元运算符

3.1.1逻辑与(&&)

&&逻辑与也称为短路逻辑与,先运算&&左边的表达式,一旦为假,后续不管多少表达式,均不再计算,一个为真,再计算右边的表达式,两个为真才为真

举例:

if(a == 0 && b==1)

3.1.2逻辑或(||)

逻辑或||的运算规则是一个为真即为真,后续不再计算,一个为假再计算右边的表达式。

举例:

if(a==0 || b==0)

3.1.3逻辑非(!)

即表示不等于

举例:

if(a != 0)

3.1.4按位与(&)

&按位与的运算规则是将两边的数转换为二进制位,然后运算最终值,运算规则即(两个为真才为真)1&1=1 , 1&0=0 , 0&1=0 , 0&0=0

举例:

int i = 3 & 5;

3的二进制位是0000 0011 , 5的二进制位是0000 0101 , 那么就是011 & 101,由按位与运算规则得知,001 & 101等于0000 0001,最终值为1

3.1.5按位或(|)

|按位或和&按位与计算方式都是转换二进制再计算,不同的是运算规则(一个为真即为真)1|0 = 1 , 1|1 = 1 , 0|0 = 0 , 0|1 = 1

举例:

int i = 6 | 2;

6的二进制位0000 0110 , 2的二进制位0000 0010 , 110|010为110,最终值0000 0110,故6|2等于6

3.1.6异或运算符(^)

^异或运算符顾名思义,异就是不同,其运算规则为1^0 = 1 , 1^1 = 0 , 0^1 = 1 , 0^0 = 0

举例:

int i = 5 ^ 9;

5的二进制位是0000 0101 , 9的二进制位是0000 1001,也就是0101 ^ 1001,结果为1100 , 00001100的十进制位是12

3.1.7左移运算符(<<)

凡位运算符都是把值先转换成二进制再进行后续的处理.

举例:

int i = 5 << 2;

5<<2的意思为5的二进制位往左挪两位,右边补0,5的二进制位是0000 0101 , 就是把有效值101往左挪两位就是0001 0100 ,正数左边第一位补0,负数补1,等于乘于2的n次方,十进制位是20

3.1.8右移运算符(>>)

凡位运算符都是把值先转换成二进制再进行后续的处理.

举例:

int i = 5 >> 2;

5的二进制位是0000 0101,右移两位就是把101左移后为0000 0001,正数左边第一位补0,负数补1,等于除于2的n次方,结果为1

3.1.9取反运算符(~)

取反就是1为0,0为1

规律:正整数N取反结果为:负(N+1);负整数-N取反结果为:N-1

举例:

int i = ~5;

5的二进制位是0000 0101,取反后为1111 1010,值为-6

3.1.10无符号右移运算符(>>>)

正数无符号右移

无符号右移运算符和右移运算符的主要区别在于负数的计算,因为无符号右移是高位补0,移多少位补多少个0。

举例:

int i = 15 >>> 2;

15的二进制位是0000 1111 , 右移2位0000 0011,结果为3

负数无符号右移

举例:

long i = -6 >>> 3;

-6的二进制是6的二进制取反再加1,6的二进制也就是0000 0000 0000 0000 0000 0000 0000 0110,取反后加1为1111 1111 1111 1111 1111 1111 1111 1010,右移三位0001 1111 1111 1111 1111 1111 1111 1111

4.int & 0xFF的含义

点击查看原文

在将byte字节转为Hex十六进制时,会使用 & 0xFF将字节值处理一下,如下图所示:

原因:

Java基础数据类型长度:

byte=1个字节=8位二进制

计算机存储数据机制:正数存储的二进制原码,负数存储的是二进制的补码。  补码是负数的绝对值反码加1。

对于正数(00000001)原码来说,首位表示符号位,反码 补码都是本身

对于负数(100000001)原码来说,反码是对原码除了符号位之外作取反运算即(111111110),补码是对反码作+1运算即(111111111)

举例:

byte[]  b = new byte[5];

b[0] = -12;

而-12 的绝对值原码是:0000 1100  取反: 1111 0011  加1:  1111 0100

byte --> int   就是由8位变 32 位 高24位全部补1: 1111 1111 1111 1111 1111 1111 1111 0100 ;

0xFF的二进制表示就是:1111 1111。   高24位补0:0000 0000 0000 0000 0000 0000 1111 1111;

-12的补码与0xFF 进行与(&)操作  最后就是0000 0000 0000 0000 0000 0000 1111 0100

byte类型的数字要&0xff再赋值给int类型,其本质原因就是想保持二进制补码的一致性。

 

当byte要转化为int的时候,高的24位必然会补1,这样,其二进制补码其实已经不一致了,&0xff可以将高的24位置为0,低8位保持原样。这样做的目的就是为了保证二进制数据的一致性。

有人问为什么上面的式子中b[0]不是8位而是32位,因为当系统检测到byte可能会转化成int或者说byte与int类型进行运算的时候,就会将byte的内存空间高位补1(也就是按符号位补位)扩充到32位,再参与运算。

5.为什么java中中文转byte字节数组出现负数

点击查看原文

GBK采用双字节8位表示dao,总体编码范du围为 8140 -- FEFE,首字节在zhi 81 -- FE 之间,尾字dao节在 40 -- FE 之间。

ASCII是7位编码内,只使用前7位,第容8位补0,所以转换成整数始终为正数,而GBK是8位编码,也就是说一个字节中的第8位可以为1,如1010 1101,而将其转换成byte类型时,byte值为10101101,以补码存储,第8位被当成符号位,当然是负数了,值为:-83。

“何”字的GBK编码是:BA CE(1011 1010 1100 1110),两个字节第8位都为1,对byte类型来说,都被理解为最高位符号位。这样值就变成-70和-50了。

;