为什么将bytes/chars
写入流的某些方法需要int
而不是byte/char
??
有人在in
t而不是char
时告诉我:
因为java中的char
只有2个字节的长度,对于已经使用的大多数字符符号都可以,但是对于某些字符符号(中文或其他),字符用超过2个字节表示,因此我们改为使用int。
这个解释与真相有多接近?
编辑:
我使用stream
字来表示二进制和字符流(不仅仅是二进制流)
感谢。
答案 0 :(得分:5)
有人告诉我int而不是char:因为java中的char只有2个字节长度,大多数字符符号已经在使用,但是对于某些字符符号(中文或其他),该字符正在表示超过2个字节,因此我们使用int。
假设此时您正在专门讨论Reader.read()
方法,那么您所叙述的“某人”的陈述其实不正确。
确实,某些Unicode代码点的值大于65535,因此无法表示为单个Java char
。但是,Reader
API实际上会生成一系列Java char
值(或-1),而不是一系列Unicode代码点。这在javadoc中明确说明。
如果您的输入包含(适当编码的)Unicode代码点大于65535,那么您实际上需要两次调用read()
方法才能看到它。你会得到一个UTF-16代理对;即,在一起的两个Java char
值代表代码点。实际上,这符合Java String,StringBuilder和StringBuffer类的工作方式;它们都使用基于UTF-16的表示......带有嵌入的代理对。
Reader.read()
返回int
而不是char
的真正原因是允许它返回-1
以表示没有更多字符需要读取。同样的逻辑解释了为什么InputStream.read()
会返回int
而不是byte
。
假设,我认为Java设计者可以指定read()
方法抛出异常来表示“流结束”条件。但是,这只会将一个潜在的错误源(无法测试结果)替换为另一个(未能处理异常)。此外,异常相对昂贵,并且流的结束并非真正意外/异常事件。简而言之,目前的方法更好,IMO。
(Reader
API的16位性质的另一个线索是read(char[], ...)
方法的签名。如果未使用代理对,如何处理大于65535的代码点?)< / p>
修改强>
DataOutputStream.writeChar(int)
的情况确实有点奇怪。但是,javadoc明确指出该参数被写为2字节值。实际上,实现清楚地只将底部的两个字节写入底层流。
我认为没有充分理由这样做。无论如何,有一个bug数据库条目(4957024),标记为“11-Closed,Not a Defect”,并带有以下注释:
“这不是一个很好的设计或借口,但它太过于让我们改变了。”
...这是一种承认 是一种缺陷,至少从设计的角度来看。
但这不值得大惊小怪,IMO。
答案 1 :(得分:3)
我不确定你指的是什么,但也许你在考虑InputStream.read()?它返回一个整数而不是一个字节,因为返回值被重载也表示流的结尾,表示为-1。由于有257个不同的可能返回值,因此一个字节不足。
否则,或许您可以提供一些更具体的例子。
答案 2 :(得分:2)
有一些可能的解释。
首先,正如一些人已经注意到的那样,可能是因为read()
必然会返回一个int,因此可以认为write()接受一个int来避免强制转换是优雅的:
int read = in.read();
if ( read != -1 )
out.write(read);
//vs
out.write((byte)read);
其次,避免其他的转换案例可能会很好:
//write a char (big-endian)
char c;
out.write(c >> 8);
out.write(c);
//vs
out.write( (byte)(c >> 8) );
out.write( (byte)c );
答案 3 :(得分:0)
最大可能的代码点是0x10FFFF是正确的,它不适合char。但是,流方法是面向字节的,而writer方法是16位。 OutputStream.write(int)写入一个字节,而Writer.write(int)只查看低16位。
答案 4 :(得分:0)
在Java中,Streams用于原始字节。要编写字符,可以在Writer中包装Stream。
虽然Writer
确实有write(int)
(写入16个低位;它是一个int因为字节太小而短,因为它被签名而太小),你应该使用而是write(char[])
或write(String)
。
答案 5 :(得分:0)
可能与read()方法对称,返回一个int。没什么大不了的。