与具有两个代码单元的字符一起使用的Java字符

与具有两个代码单元的字符一起使用的Java字符,java,unicode,utf-16,surrogate-pairs,astral-plane,Java,Unicode,Utf 16,Surrogate Pairs,Astral Plane,摘自Core Java,第1卷,第9版,第。69: 人物ℤ 在UTF-16编码中需要两个代码单元。召唤 String sentence = "ℤ is the set of integers"; // for clarity; not in book char ch = sentence.charAt(1) 不返回空格,而是返回的第二个代码单元ℤ. 但似乎语句.charAt(1)确实返回了一个空格。例如,以下代码中的if语句的计算结果为true String sentenc

摘自Core Java,第1卷,第9版,第。69:

人物ℤ 在UTF-16编码中需要两个代码单元。召唤

String sentence = "ℤ is the set of integers"; // for clarity; not in book
char ch = sentence.charAt(1)
不返回空格,而是返回的第二个代码单元ℤ.

但似乎
语句.charAt(1)
确实返回了一个空格。例如,以下代码中的
if
语句的计算结果为
true

String sentence = "ℤ is the set of integers";
if (sentence.charAt(1) == ' ')
    System.out.println("sentence.charAt(1) returns a space");
为什么?

我正在Ubuntu 12.10上使用JDK SE 1.7.009,如果相关的话。

请解释一下:

字符串表示UTF-16格式的字符串,其中 补充字符由代理项对表示(请参见 字符类中的部分Unicode字符表示法 (更多信息)。索引值指的是字符代码单位,因此 补充字符使用字符串中的两个位置

简而言之,这本书是错的


编辑以从下面的评论中添加:昨晚我没有想到的是,你在问题中使用的字符实际上不是他们所说的字符,他们真正想要的是当你有一个需要四个字节而不是两个字节的字符时。Javadoc中的上述段落链接到另一个Javadoc;关于这件事的后果

根据文档,内部表示为utf-16,因此
charAt()
为您提供了两个代码点。如果您对查看单个代码点感兴趣,可以使用此代码(从此处):

final int length=句子.length();
对于(int offset=0;offset
听起来书上说的是ℤ' 不是中的UTF-16字符,但实际上是

Java对不在基本多语言平面中的字符使用UTF-16和代理项对。自从ℤ' (0x2124)位于基本多语言平面中,由单个代码单元表示。在您的示例
语句中,charAt(0)
将返回'ℤ', 和
语句。charAt(1)
将返回“”

由代理项对表示的字符由两个代码单元组成<代码>句子.charAt(0)将返回第一个代码单位,而
句子.charAt(1)
将返回第二个代码单位

见:

字符串表示UTF-16格式的字符串,其中 补充字符由代理项对表示(请参见 字符类中的部分Unicode字符表示法 (更多信息)。索引值指的是字符代码单位,因此 补充字符使用字符串中的两个位置


霍斯特曼说的是需要两个UTF-16编码单元的“Z”。 请看下面的代码:

public class Main {
    public static void main(String[] args)
    {
        String a = "\uD83D\uDE02 is String";
        System.out.println("Length: " + a.length());
        System.out.println(a.charAt(0));
        System.out.println(a.charAt(1));
        System.out.println(a.charAt(2));
        System.out.println(a.charAt(3));
    }
}

在IntelliJ Idea中,我甚至不能将4字节字符粘贴为一个字符,因为在粘贴此表情符号时:drat!快21秒:是啊,但是你增加了获取代码点的部分。。。我正计划编辑以补充:)据我所知,这本书在基本原则上是正确的,只是在作为例子的角色上是错误的。如果ℤ 如果被U+1D419数学粗体大写字母Z替换,则演示将是正确的(但读者可能仍然会感到困惑)。因此。。。问题其实就是问题所在。同意如果它是一个需要两个代码单位的字符,那么事情就不同了。它目前没有包含任何关于上述内容的内容(除了说部分编号错误),但作为参考,这里有一个。这本书有没有说这个字形代表什么代码点?许多代码点看起来都是相似的。一个没有书中bug的更直接的问题是:-)你会遇到“麻烦”的地方是一个Unicode补充字符,它需要4个字节来表示,而不是2个字节(Java的
char
)。“每个人两个字节就足够了”-Bill Gåtes@GregKopff-是的,但无论怎样,这都会变得丑陋,因为
char
也停止工作。
charAt()
给出了一个代码单元,它可以是一个代码点(对于BMP字符)或一个代理代码单元,可以非正式地称为“半个代码点”。不要使用两个代码点。可以使用
offset=句子。offsetByCodePoints(offset,1)
而不是使用
offset+=Character.charCount(代码点)
public class Main {
    public static void main(String[] args)
    {
        String a = "\uD83D\uDE02 is String";
        System.out.println("Length: " + a.length());
        System.out.println(a.charAt(0));
        System.out.println(a.charAt(1));
        System.out.println(a.charAt(2));
        System.out.println(a.charAt(3));
    }
}