本帖最后由 001可望成功 于 2014-7-13 10:55 编辑
前几天提了一个问题是:java中流操作的-1问题?但是大家伙都说我好像有点专牛角尖了,这不是java要研究的问题。
今天看见一位小伙伴提了一个类似的问题:“既然字节流的操作是按照字节进行读取的,那么每一次read能读取几个字节的长度呢
它定义的read方法返回的是int型,那么也就是说一次读取4个字节? 要是只读取一个字节那么用int型接收岂不是浪费了3byte的空间么”。好多小伙伴的回复都表示没有注意到这个问题,所以专门发表这篇帖子,希望能和大家互相交流一下,如果有什么不对的地方,还望大家多多指教。
查看API文档可以知道:read方法一次读取数据的一个字节
public abstract int read() throws Exception
从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。public abstract void write(int b) throws Exception
将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。
既然java是以字节的方式读取出来,然后又以字节的方式存了起来,那为什么中间要将byte类型向上转型为int呢,这样岂不是多此一举吗?
既然詹姆斯·高斯林能编写出java,就应该不会犯这样的错误。那问题就在read方法这了,read方法读到流末尾的时候,返回-1,问题是不是出在这呢,字节都是由0和1组成的,而-1的二进制表示是1000 0001,在计算机内存中表示是1111 1111(用的是补码),流在读取字节的时候,很容易出现1111 1111这种情况,这样就会返回一个“-1”的字节(前提是byte有符号位,无符号位的时候8个1是255),如果read方法和write方法都直接操作byte,那么这时流操作以为读到了结尾,就会结束读取,后面的数据也就丢失了。为了避免这种情况的出现,将byte向上转型为int,正数在前面补24个0,负数在前面补24个1,例如byte型-1,转为int后是32个1,但这32个1转为十进制后任然是-1啊,也没有起到效果啊。后来,在Java源码ByteArrayInputStream.java中终于找到了证据:
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
将每一个独到的字节与0xff(十进制是255(16平方-1,因为最小的是0),二进制是00000000 00000000 00000000 11111111)按位与,将-1转换为255,这样只有当pos=count(即当前数=buf数组长度的时候)才返回-1。很好的解决了这个问题
而write方法存储的时候,只写最低八位,24个高位都将被忽略。这样又将int型存储为了byte型。大体上就是这个意思,想了好长时间才明白的。
|