java inputStream中的int转byte和byte转int的方式和注意事项

小知识:

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; 原理类似。

 

有些东西看似简单,原理还是有点复杂,仔细研究才能运用自如,文章纯属手敲,如有错误,欢迎斧正和批评,谢谢!

 

转载请注明出处,谢谢 !

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值