为什么Java的OutputStream.write()方法需要传入整数参数但是写入的是字节?

34

我正在编写一个OutputStream,刚刚注意到OutputStream接口中有这个内容:

   public abstract void write(int b) throws IOException;

这个调用只向流写入一个字节,但为什么它需要以整数作为参数?

5个回答

26

7
如果你写(-1),会发生什么?它会关闭流吗?:-) - Ken
6
换句话说,write(int) 的存在是为了与 read() 对称。这并不算太糟糕,当你思考它时。好的回答。 - skaffman
我在这方面没有谷歌(我尝试过)。如果有链接能够证明/否定我的假设,那就太好了。 - sfish
这个回答似乎不相关。问题是关于write()而不是读取。 - erickson
那么实际上,write 写入 2 个字节? - Tomáš Zato
显示剩余4条评论

12

最近我一直在处理字节,它们有些令人讨厌。如果稍微有点刺激就会转换为int类型,并且没有特定的方法把一个数字转换为字节--比如8L会给你一个长整型的值8,但是对于字节,你必须写成(byte)8。

除此之外,除非你使用数组(甚至在使用数组时也可能),否则它们几乎总是以int形式存储在内部。

我认为它们只是假定使用字节的唯一原因是要进行输入/输出,实际上你确实需要8位,但在内部它们希望你总是使用int。

顺便说一句,字节的性能可能会更差,因为它总是需要掩码...

至少我记得几年前读过这样的内容,现在可能已经改变了。

作为针对您具体问题的示例答案,如果一个函数(f)接受一个字节,并且你有两个字节(b1和b2),那么:

f(b1 & b2)

这样不行,因为b1和b2会被升级为int类型,而int类型无法自动降级(精度丢失)。所以你需要编写如下代码:

f( (byte)(b1 & b2) )

这会变得很烦人。

而且不要问为什么b1和b2会进行上转换 - 我最近也在咒骂它!


5
<开始发泄> 在Java中进行字节操作充满了这种坑(通常是那些几乎无法在设计时捕获的类型)。为什么编译器不能弄清楚new byte[] {0x01, 0x02}是一个字节数组?为什么我必须写new byte[] {(byte)0x01, (byte)0x02}?<结束发泄> - Kevin Day
1
你只需要转换大于0x7F的值,因为字节是有符号的。这并不令人烦恼。这比拥有一堆无符号/有符号字符要好得多。使用IDE,它会检查类型安全性并为您进行转换。掩码操作是一条指令,不会影响性能。 - Denis Tulskiy

7
根据OutputStream的Javadoc,此函数会忽略高24位。我认为该方法是为了兼容性而存在的:因此您不需要先转换为字节,只需传递整数即可。

敬礼


2
兼容性是指与什么兼容呢? - skaffman
1
兼容性可能不是很准确的描述,我们倒不如称之为简单或程序员友好。 ;o) - Atmocreations
write(int)write(byte[])之间的不连续性非常明显,特别是当您看到write(byte[])的默认实现只是在循环中调用write(int)时。 - skaffman
1
此外,字节对象没有数字文字转换器 - 即5是int,5l是long,但没有5b或类似的东西。 - aperkins
5
我认为 Atmocreations 意味着 write(int) 的目的是为了避免用户进行显式转换。就我个人而言,我宁愿使用 write(byte) 这样的规定,而不必阅读文档才能知道有 3/4 的位被忽略。 耸肩 - Grant Wagner
显示剩余3条评论

3
Java IOStream类自Java 1.0以来就是Java的一部分。这些类只处理8位数据。我猜测接口是这样设计的,因此一个write(int b)方法将被调用以处理int、short、byte和char值。所有这些都被提升为int。实际上,由于大多数JVM运行在32位机器上,int原语是处理最有效的类型。编译器可以自由地使用32位存储诸如字节之类的类型。有趣的是,byte[]确实被存储为8位字节的序列。这是有道理的,因为数组可能非常大。然而,在单个原始值(如int或byte)的情况下,运行时实际占用的空间并不重要,只要行为符合规范即可。

更多背景:

http://www.java-samples.com/showtutorial.php?tutorialid=260

IOStream类的假设是,即使传入int类型,调用方实际上只关心数据的最低8位。 只要调用方知道它确实在处理字节,这就没问题,但当底层数据实际上是使用其他字符编码(例如多字节Unicode)的文本时,这就成为一个问题。 这就是为什么读取器类在Java 1.1中引入的原因。 如果您关心文本数据和性能,则IOStream类更快,但读取器类更具可移植性。

2
也许这是因为字节默认是有符号的,而文件将字节存储为无符号值。这就是为什么read()返回一个int - 以便在$FF时给出255而不是-1。同样,write(int)也是如此,你不能将$FF存储为byte中的255。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接