Java 从流中读取byte的奇怪现象,出现负值,详解

其实一点都不奇怪,下面我们来详细分析

首先看下面一段代码,代码的意思是将128写入到文件中,再从文件中读出一个byte输出

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    int a = fis.read();
    System.out.println(a);

输出结果为:

128

这符合我们的直观感觉,写入128,读出来也是128

下面我们修改一下代码,将数据度入到byte数组里,看看输出会是什么样子,代码如下

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    byte[] b = new byte[1];
    fis.read(b, 0, 1);
    System.out.println(b[0]);

输出结果为

-128

好了,“奇怪”的现象出现了,这是为什么呢?

首先,我们需要了解一些基础知识,在Java中,byte的范围为 -128 ~ 127,并没有128这个数值;其次,读者需要了解一下负数在Java中如何表示(即原码、反码、补码的相关知识,请读者自行谷歌)。

下面,我们来分析一下出现 -128 的原因:

首先,fos.write(128) 表示写入 “128” 所代表的字节,即 1000 0000,也就是说,文件中当前包含一个字节,8位依次为 1 0 0 0 0 0 0 0

当我们调用fis.read()时,该方法会返回一个无符号byte,也就说直接将1000 0000翻译为128,大家可以去看该方法的说明,返回值的范围为0 ~ 255;所以我们得到了 128 的输出;

当我们调用fis.read(b, 0, 1)时,相当于把文件中第一个字节读入到了b[0]中,此时b[0]的二进制表示为1000 0000,根据负数在Java中的表示方法,我们可以计算出,该二进制序列的数值为 -128,也就是说这个过程并没有将其转化为无符号数值的过程,所以我们得到了 -128 的输出。

那么,我们如何解决这个问题呢?

首先,我们需要看一下fos.write(int a)这个方法,它的功能是写入a代表的byte值,也就是说,该函数实际上是将a 的后八位写入到文件中 , 所以作者建议在使用该方法时,为了避免产生歧义,a 的范围最好在 0 ~ 255 之间,初学者最好在 0 ~ 127 之间。(具体原因可以结合负数的表示规则自己想想哦~)。

回归正题,我们如何解决上文中的问题呢,即 “写入128、读出-128” 的问题,我们可以用下面的代码来解决。

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    byte[] b = new byte[1];
    fis.read(b, 0, 1);
    System.out.println(b[0] & 0xff);

也就是说,用b[0] & 0xff的方法得到b[0]的无符号值。

插入一个小问题,就是,b[0] | 0xff得到的是一个负值,而 & 得到的却是一个正值。这里根据作者的猜测,可能是如下原因,主要和 & 运算的步骤有关:

进行 b[0] & 0xff运算时的步骤如下:

  1. 因为0xff默认应该用int来保存,所以首先将 b[0] 强制转化为 int 类型表示,b[0] 的数值为-128,所以其二进制表示为11111111 11111111 11111111 10000000
  2. 0xff的二进制表示为 00000000 00000000 00000000 11111111
  3. 这两个数做 & 运算后,得到 00000000 00000000 00000000 10000000,其表示的值为128

“或 运算”的过程类似,读者可以自己推理一下

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值