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

Is an instance of a Java string always valid 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 语言测试用例?

编辑:有人将问题标记为 [ 的可能重复 我只能说,String 和a char[] 以及为什么前者至少在理论上可以保证其内容而后者没有的原因。我不是在问关于数组的问题,我是在问关于 Strings.

的问题

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

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

换句话说,它的工作方式更像是一个字符单元缓冲区——一个 16 位值的缓冲区——而不是合法的 UTF-16 序列。这确实是 String 类型的必要方面。

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

没有。 String 只是 char[]:

的无限制包装
char data[] = {'\uD800', 'b', 'c'};  // Unpaired lead surrogate
String str = new String(data);

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

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