面试官:字节流中的read()方法是读取一个字节,那为什么返回值是int型?

面试过程中可能会遇到面试官问这个问题:

字节流中的read()方法是读取一个字节,那为什么返回值是int型?今天来简单说一下

首先看下JDK文档

可以看到文档对read方法的描述都是返回一个字节的数据,但是它的返回的却是int型,那这是为什么呢?

而且InputStream类里的read( )是一个抽象的方法,这是一个模板方法模式,InputStream类里写好 流操作的大体逻辑,但是read()这个方法等着子类去实现,那咱们就看下InputStream的一个子类 BufferedInputStream 类里具体实现的read( )方法

可以看到最后它返回的时候& 0xff 也就是32位的255,这是为什么呢?

是因为在读一个文件的时候有可能会遇到读到连续8个1的情况,而8个1的十进制正好是-1,这就和结束标志那个-1冲突了,就会出现有可能还没读完但是由于你返回-1了导致结束了。

那么这个怎么解决呢?
现在有个解决方案,那就是让每次读到的一个字节8位的数据都提升成int型的,然后&上int型的255,这样既能让最后的8位保持原来一个字节8位的数据,而且还可以避免出现-1的情况。

举个例子:00000001   这是1,这个数的负数 是原数取反+1,即 11111110+1  -----> 11111111

所以把8位的-1(也就是00000001) 提升成32位的时候,

就成了 0000000 00000000 00000000 00000001取反 -----> 1111111  11111111   11111111  11111110

再加1 ----->1111111  11111111   11111111  11111111
大家都知道1是true,0是false,所以这时候再&与上0000000 00000000 00000000 11111111也就是32位的255

1111111  11111111   11111111  11111111      -1
&
0000000 00000000 00000000 11111111    255
--------------------------------------------------------------------
0000000 00000000 00000000 11111111

所以这么做完以后,就算读到了11111111也不怕和结束标识-1冲突了,因为最后的结果是0000000 00000000 00000000 11111111

这个数根本不是-1。所以冲突问题解决,最关键的是,冲突问题解决的同时,提升完的这个数据的最后8位还保留了之前的数据的原样。
所以咱们可以总结一下:为了避免遇到读到连续8个1的情况,read方法在做提升,把读取到的byte转换成int,而且返回的数据是&上int型255,这样做既能避免-1出现,又能让返回的int型数据的最后8位保留的是原数据,但是由于read把读取的数据做了提升,真正有效的数据只有最后8位,那所以wtite方法写的时候就需要把最后一个字节8位的数据写出去就行了,如果不这么做的话,那写完以后文件的大小将是读取过来文件大小的4倍,所以read是在做提升,write是在做强转(只要最后8位,其他高位上的0全抛弃)

最后有一个小技巧:如果要想只保留最后8位就&上255,要想只保留后4位就&上16

发布了108 篇原创文章 · 获赞 103 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/ju_362204801/article/details/104715442
今日推荐