一些使用新字符串的字节数组(字节[],“UTF-8”)在jdk 1.7和1.8中返回不同的结果
byte[] bytes1 = {55, 93, 97, -13, 4, 8, 29, 26, -68, -4, -26, -94, -37, 32, -41, 88};
String str1 = new String(bytes1,"UTF-8");
System.out.println(str1.length());
byte[] out1 = str1.getBytes("UTF-8");
System.out.println(out1.length);
System.out.println(Arrays.toString(out1));
byte[] bytes2 = {65, -103, -103, 73, 32, 68, 49, 73, -1, -30, -1, -103, -92, 11, -32, -30};
String str2 = new String(bytes2,"UTF-8");
System.out.println(str2.length());
byte[] out2 = str2.getBytes("UTF-8");
System.out.println(out2.length);
System.out.println(Arrays.toString(out2));
bytes2使用新的String(byte [],“UTF-8”),结果(str2)在jdk7和jdk8中不相同,
但是字节1是相同的。 bytes2有什么特别之处?
测试“ISO-8859-1”代码,bytes2的结果与jdk1.8中的相同!
jdk1.7.0_80:
15
27
[55, 93, 97, -17, -65, -67, 4, 8, 29, 26, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, 32, -17, -65, -67, 88]
15
31
[65, -17, -65, -67, -17, -65, -67, 73, 32, 68, 49, 73, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, 11, -17, -65, -67]
jdk1.8.0_201
15
27
[55, 93, 97, -17, -65, -67, 4, 8, 29, 26, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, 32, -17, -65, -67, 88]
16
34
[65, -17, -65, -67, -17, -65, -67, 73, 32, 68, 49, 73, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, 11, -17, -65, -67, -17, -65, -67]
最佳答案
简短答案:
在第二个字节数组中,最后2个字节:[-32,-37](0b11011011_11100000)编码为:
By JDK 7: [-17, -65, -67] which is Unicode character 0xFFFD ("invalid character"),
By JDK 8: [-17, -65, -67, -17, -65, -67] which is 2 of 0xFFFD characters.
长答案:
数组中的某些字节序列似乎不是有效的UTF-8序列。
让我们考虑以下代码:
byte[] bb = {55, 93, 97, -13, 4, 8, 29, 26, -68, -4, -26, -94, -37, 32, -41, 88};
for (byte b : bb) System.out.println(Integer.toBinaryString(b & 0xff));
它将打印(为便于阅读,我手动添加了下划线):
__110111
_1011101
_1100001
11110011
_____100
____1000
___11101
___11010
10111100
11111100
11100110
10100010
11011011
__100000
11010111
_1011000
如您所读,utt-8编码的UTF-8 Wikipedia article字符串,使用以下二进制序列:
0xxxxxxx -- for ASCII characters
110xxxxx 10xxxxxx -- for 0x0080 to 0x07ff
1110xxxx 10xxxxxx 10xxxxxx -- for 0x0800 to 0xFFFF
... and so on
因此,不遵循此编码方案的每个字符都将替换为3个字节:
[-17,-65,-67]
以二进制形式1110 1111 10 111111 10 111101
Unicode位为0b11111111_11111101
Unicode十六进制为0xFFFD(Unicode的“无效字符”)
您的代码打印出的数组的唯一区别是以下字符的处理方式,即第二个数组末尾的2个字节:
[-32, -30] is 0b11100000_11100010, and this is not valid UTF-8
JDK 7为此序列生成了一个0xFFFD字符。
JDK 8为此序列生成了两个0xFFFD字符。
RFC-3629标准没有关于如何处理无效序列的明确说明,因此似乎在JDK 8中他们决定为每个无效字节生成0xFFFD,这似乎更正确。
另一个问题是,为什么当您不应该这样做时,为什么尝试解析诸如UTF-8字符之类的原始非UTF-8字节?