Java字符串的实例是否始终有效UTF-16?

时间:2015-08-27 03:48:07

标签: java unicode character-encoding char utf-16

对于任何给定的Java字符串s,我想知道s表示的字符数组保证是否是有效的UTF-16字符串,例如:

final char[] ch = new char[s.length()];
for (int i = 0; i < ch.length; ++i) {
    ch[i] = s.charAt(i);
}
// Is ch guaranteed to be a valid UTF-16 encoded string?

如果没有,那些产生无效UTF-16的简单Java语言测试用例是什么?

编辑:有人将此问题标记为[Is a Java char array always a valid UTF-16 (Big Endian) encoding?的可能副本我只能说,String和{char[]之间存在差异{1}}以及为什么前者至少在理论上可以保证后者不能保证其内容的原因。我没有问过关于数组的问题,我问了一个关于String的问题。

2 个答案:

答案 0 :(得分:3)

没有。 String只是char[]的无限制包装:

char data[] = {'\uD800', 'b', 'c'};  // Unpaired lead surrogate
String str = new String(data);

要测试格式正确的UTF-16数据的Stringchar[],您可以使用CharsetEncoder

CharsetEncoder encoder = Charset.forName("UTF-16LE").newEncoder();
ByteBuffer bytes = encoder.encode(CharBuffer.wrap(str)); // throws MalformedInputException

答案 1 :(得分:2)

不可以,在程序执行期间,不保证Java String的实例在所有点都包含有效的UTF-16代码单元序列(即16位值)。它也必须以这种方式工作。

这是微不足道的证明。想象一下,您有一系列代码点(通常以32位整数存储的21位数量),您希望将其附加到一个字符串,一次一个字符单元。如果其中一些代码点位于基本多语言平面之上(即,值> 0xFFFF,因此需要超过16位来保存它们),那么当一次添加一个16位代码单元时,您将拥有一个String期间,String只有一个主要的代理,但还没有所需的尾随代理。

换句话说,它更像是一个char-unit缓冲区 - 一个16位值的缓冲区 - 而不是一个合法的UTF-16序列。这确实是String类型的必要方面。

只有在将其转换为特定编码时才会出现问题,因为不匹配,翻转或单独的代理在三种UTF格式中都不合法,因此编码器无法代表它们。