最近在做代码相关的优化,找到了一个二进制转十六进制的方法:
/**
* 二进制转16进制
* @param bin
* @return 16进制字符串
*/
public static String asHex(byte[] bin) {
//一个byte为8位,一个十六进制为4位,所以长度乘以2
StringBuilder bfHex = new StringBuilder(bin.length * 2);
int i;
for (i = 0; i < bin.length; i++) {
if (((int) bin[i] & 0xff) < 0x10)
//如果小于10,那么转化为16进制需要往前面加0,凑足两位
bfHex.append("0");
//转为为16进制字符串
bfHex.append(Integer.toString((int) bin[i] & 0xff, 16));
}
return bfHex.toString();
}
0XFF = {[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1]};
int
类型的数字 &0XFF
,就是将这个数字的高24位全部置为0;byte
转化为32位的 int
类型,它的数值大小不会发生任何变化;0
;1
;我们先看一段代码:
public static void main(String[] args) {
System.out.println(Integer.toBinaryString(1));
System.out.println(Integer.toBinaryString(-1));
}
输出结果:
1
11111111111111111111111111111111
1 = byte[00000001] = int {000000000000000000000000000000001} = 0x1
-1 = byte[11111111] = int {11111111111111111111111111111111} = 0xffffffff
我们在做二进制转16进制的时候,需要的是数据的正确性而不是数值的正确性。所以我们进行 0XFF
的时候抹掉了高24位,确保了数据二进制补码的完整新(同时也解释了转化的16进制如果小于10需要在前面加0的原因)。
byte&0xff.png
我们从 BufferedInputStream.java
源代码中都可以找到获取下一个字节的方法 int read()
,最后的得到的字节也是需要 &0xff
转化为 int
类型进行返回的,这样才能保证数据的完整性。
[+1]原 = 0000 0001
[-1]原 = 1000 0001
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值.;
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
正数的反码是其本身; 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反;
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
正数的补码就是其本身; 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1);
补码的设计有意识的引用了模运算在数理上对符号位的自动处理,利用模的自动丢弃实现了符号位的自然处理,仅仅通过编码的改变就可以在不更改机器物理架构的基础上完成的预期的要求(将减法变为加法),所以补码沿用至今。
将钟表想象成是一个1位的12进制数. 如果当前时间是6点, 我希望将时间设置成4点, 需要怎么做呢?我们可以:
2,3方法中的mod是指取模操作, 16 mod 12 =4 即用16除以12后的余数是4。 同余定理 所以钟表往回拨(减法)的结果可以用往前拨(加法)替代!
首先要确定二进制中模到底是多少。
在二进制加法运算中膜有0~127,膜为128(128个数),即为2的n次方。 2的n次方减一 = A + A[反] 2的n次方 = A + A[反] + 1 A[补] = A[反] + 1 2的n次方 = A + A[补]
所以可以将负数用补码方式进行变化进行 加操作
,符号为也可以参与运算。