Java 8 UTF-8编码问题(java bug?)

时间:2014-08-20 12:12:31

标签: java encoding utf-8 java-8

使用UTF-8编码创建字符串时存在不一致。

运行此代码:

public static void encodingIssue() throws IOException {
    byte[] array = new byte[3];
    array[0] = (byte) -19;
    array[1] = (byte) -69;
    array[2] = (byte) -100;

    String str = new String(array, "UTF-8");
    for (char c : str.toCharArray()) {
        System.out.println((int) c);
    }
}

在Java 1.8.0_20(及更早版本)上,我们得到了结果

 65533

在Java 1.7和1.6上,我们得到了正确的结果:

 57052

您是否遇到过此错误?有解决方法吗?

这种不一致也体现在Shift_JIS,JIS_X0212-1990,x-IBM300,x-IBM834,x-IBM942,x-IBM942C,x-JIS0208上,但显然UTF-8更为紧迫。

3 个答案:

答案 0 :(得分:12)

Modified UTF-8编码的属性用于存储代理对(甚至是该范围的未配对字符),如单个字符。如果声称使用标准UTF-8的解码器使用“修改的UTF-8 ”,则会出错。这似乎已经用Java 8修复了。

您可以使用指定的方法可靠地读取此类数据,以使用“修改的UTF-8 ”:

ByteBuffer bb=ByteBuffer.allocate(array.length+2);
bb.putShort((short)array.length).put(array);
ByteArrayInputStream bis=new ByteArrayInputStream(bb.array());
DataInputStream dis=new DataInputStream(bis);
String str=dis.readUTF();

答案 1 :(得分:5)

Java 1.6 / 1.7中收到的值是U + DEDC(低代理值)。

来自RFC 3629

  

UTF-8的定义禁止在U + D800和U + DFFF之间编码字符编号,这些字符编号保留用于UTF-16编码格式(作为代理对)并且不直接表示字符。

     

...文字省略......

     

上面的解码算法的实现必须防止      解码无效序列。例如,一个天真的实现可能      将超长UTF-8序列C0 80解码为字符U + 0000,      或代理对ED A1 8C ED BE B4进入U + 233B4。解码      无效序列可能会产生安全后果或导致其他后果      问题。

Java 8将此解码为U + FFFD(REPLACEMENT CHARACTER)。这看起来像是在Java 8中修复的错误。

答案 2 :(得分:3)

这是代理人,对吧?我不是Unicode专家,但我不认为它本身就有意义。 Java 8已更改为支持Unicode 6.2。也许它对此更严格。 65533是标准的0xFFFD替换字符,这意味着"不可表示"。是否存在需要将其解释为字符串的真实情况?因为看起来Unicode似乎已经说不再是一个角色了。