为什么ByteArrayOutputStream使用int?

也许有人可以帮助我理解,因为我觉得我错过了一些可能会影响我的程序运行的东西。

我正在使用ByteArrayOutputStream。 除非我错过了一些巨大的东西,否则这个类的重点是为其他用途创建一个byte []数组。

但是,BAOS上的“普通”写入函数采用int而不是字节( ByteArrayOutputStream.write )。

根据此( 原始数据类型 )页面,在Java中,int是32位数据类型,字节是8位数据类型。

如果我写这个代码……

int i = 32; byte b = i; 

我收到一个关于可能有损转换的警告,需要对此进行更改…

 int i = 32; byte b = (byte)i; 

我真的很困惑写(int)…

ByteArrayOutputStream只是覆盖OutputStream声明的抽象方法。 所以真正的问题是为什么OutputStream.write(int)以这种方式声明,当它声明的目标是将单个字节写入流时。 流的实现在这里是无关紧要的。

你的直觉是正确的 – 在我看来,这是一个破碎的设计。 是的,它会丢失数据,正如文档中明确指出的那样:

要写入的字节是参数b的八个低位。 b的24个高位被忽略。

在我看来, write(byte)会更加明智。 唯一的缺点是你不能在没有强制转换的情况下用文字值调用它:

 // Write a single byte 0. Works with current code, wouldn't work if the parameter // were byte. stream.write(0); 

看起来没问题,但不是 – 因为文字0的类型是int ,它不能隐式转换为byte 。 你必须使用:

 // Ugly, but would have been okay with write(byte). stream.write((byte) 0); 

对我而言,按照原样设计API并不是一个足够好的理由,但这就是我们所拥有的 – 并且自Java 1.0以来就已经有了。 不幸的是,如果没有它在整个地方发生重大变化,它现在无法修复。

为了促进0x7F以上的无符号字节,这就发生了。 int将被默默地缩小以便写入。 实际上,代码通过(byte)强制转换来实现。

正如Ingo所说:

可能的原因可能是要写入的字节通常是某些操作的结果,该操作会自动将其操作数转换为int [,如某些位操作。 因此,代码将被抛出为强制转换为字节,这不会增加理解。

这主要是因为Java虚拟机模型的堆栈讨厌byte ,但喜欢int 堆栈使用32位插槽,与int的大小相匹配。

但是你会注意到java *像byte[]引用一样 。 但那是因为数组的内容存储在堆(而不是堆栈)中。 每当特定byte被寻址并移动到堆栈( bipushsipush操作码)时,它们立即转换为整数。

但有时java实际上使用257(!)值。 当InputStream#read()返回256个值时,但当它没有内容时,它将返回-1值。 或者,可以抛出一个EOFException (就像其他一些方法那样),但java中的exception很慢。

即使你不需要OutputStream#write-1值,也OutputStream#write 它是连贯的,它会减少转换。 但是,是的,它也具有误导性。