小知识:
byte (8位),short(16位),int (32位),long(64位) 此处只列整数
有符号位的第一位表示符号,0 表示 正,1 表示 负
正数的反码:与原码相同
负数的反码:原码的符号位不变,其他位取反
正数的补码:与原码相同
负数的补码:反码+1
整数的正数在内存中显示的跟源码一样,如. int i = 1; i 在内存中就是 00000000 00000000 00000000 00000001
整数的负数在内存中显示的是补码,补码 = 反码 + 1,如 -1 的源码是 10000000 00000000 00000000 00000001,那么它的反码就是 11111111 11111111 11111111 11111110,那么它的补码就是 11111111 11111111 11111111 11111111。
正题:
int的二进制码查看:可以通过Integer.toBinaryString(num),该方法会返回int类型在内存中的二进制代码,注意 int 是32位的,正数显示的是源码,高位如果全是0的话会自动丢弃,所以脑补一下即可。
byte的二进制码查看:
public static String getByte(byte b) {
return + (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
+ (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
+ (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
+ (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1) + "";
/*
*
0x 表示16进制
>> 表示右移 b >> 7 表示 右移7位(舍弃低6位)
位与运算符(&):运算规则:两个数都转为二进制,然后从高位开始比较,如果两个数都为1则为1,否则为0。
& 0x1 的意思是:该数值与16进制的1进行位于运算,作用就是 如果最低位是 1 就取 1 ,0 就取 0,目的是获取最低位。
*
* */
}
介绍完基础后开始介绍输入流inputStream ,该类有一个重要的方法 read(),读取一个字节,并返回该字节,注意读取的是一个字节,也就是8位二进制代码,是无符号位的,取值范围是0~255 ,也就是低8位是读取的字节,其余的24位全是0 ,但是它把它放到一个int长度的数据类型中保存,根据强转规则,int 转 byte 会截取低 8位,所以 输入流中的 int 可以直接强转为 byte ,不会丢失数据。
即:int i = in.read(); byte b = (byte)i; 即可。
明白这个原理对打印日志什么的很方便,比如我想查看打印一个文件的内容,用以下代码即可(这样写只是方便理解):
public void input2(){
try(InputStream in = new FileInputStream(new File("/Users/chengong/Desktop/test.txt"))){
byte[] bytes = new byte[in.available()];
int i;
int j = 0;
while((i = in.read()) != -1){
bytes[j] = (byte)i;
j ++ ;
}
String s = new String(bytes);
System.out.println(s);
} catch (Exception e){
e.printStackTrace();
}
}
//---------------以上只是方便理解,实际小文本直接按下面代码就可以了
public void testInp(){
try(InputStream in = new FileInputStream(new File("/Users/chengong/Desktop/test.txt"))){
if(in.available()>0){
byte[] bytes = new byte[in.available()];
in.read(bytes);
String s = new String(bytes);
System.out.println(s);
}
} catch (Exception e){
e.printStackTrace();
}
}
但是重点来了,byte转为int就有问题了,因为前面说过,数值在内存中是有符号的,byte转为int的时候会考虑符号位,如果符号位是0 那么强转后是正常的,如果符号位位1,那么强转位 int 就会导致强转后的int跟最初的int不一致,原理是:
假如输入流中读取的一个字节是 10000001,该数值是无符号位的,它表示 129,读出来的int是
00000000 00000000 0000000 10000001
强转为byte后只截取低8为,即 10000001,整数是有符号位的,该值是 -1 的源码。补码是 11111111。
那么该值再强转为int后就会考虑符号位,符号位保留,高位补 0 ,即 1000000 00000000 00000000 00000001。补码是32个1。
因为该值之前是 00000000 00000000 0000000 10000001,所以就出问题了。
那么怎么解决呢?
对强转前的byte做个判断,如果是正,即符号位为0,就直接强转,没问题。
如果是负,即符号为 1,就让该值与 11111111 11111111 11111111 00000000 进行位异或运算^ ,即 byte^-256。
位异或运算(^):两个数转为二进制,然后从高位开始比较,如果相同则为0,不相同则为1。
11111111 11111111 11111111 10000001
^
11111111 11111111 11111111 00000000
=00000000 00000000 0000000 10000001。
所以 int i = byte > 0?byte:byte^-256; 即可。
也可以 int i = byte > 0?byte:byte+256; 原理类似。
有些东西看似简单,原理还是有点复杂,仔细研究才能运用自如,文章纯属手敲,如有错误,欢迎斧正和批评,谢谢!
转载请注明出处,谢谢 !