Java charAt用于具有两个代码单元的字符

来自Core Java ,第一卷。 1,第9版,p。 69:

字符ℤ需要两个UTF-16编码的代码单元。 调用

String sentence = "ℤ is the set of integers"; // for clarity; not in book char ch = sentence.charAt(1) 

不返回空格而是返回second的第二个代码单元。

但似乎sentence.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.0_09,如果它是相关的。

听起来这本书说’ℤ’不是基本多语言平面中的UTF-16字符,但实际上它是。

Java将UTF-16与代理对一起用于不在基本多语言平面中的字符。 由于’ℤ’(0x2124)在基本多语言平面中,因此它由单个代码单元表示。 在你的例子中, sentence.charAt(0) .charAt sentence.charAt(0)将返回’ℤ’,而sentence.charAt(1)将返回”。

由代理对表示的字符具有构成该字符的两个代码单元。 sentence.charAt(0)将返回第一个代码单元,而sentence.charAt(1)将返回第二个代码单元。

请参阅http://docs.oracle.com/javase/6/docs/api/java/lang/String.html :

String表示UTF-16格式的字符串,其中补充字符由代理项对表示(有关更多信息,请参阅Character类中的Unicode字符表示forms一节)。 索引值是指char代码单元,因此补充字符在String中使用两个位置。

根据文档, String在内部表示为utf-16,因此charAt()为您提供了两个代码点。 如果您有兴趣查看各个代码点,可以使用此代码(来自此答案 ):

 final int length = sentence.length(); for (int offset = 0; offset < length; ) { final int codepoint = sentence.codePointAt(offset); // do something with the codepoint offset += Character.charCount(codepoint); } 

Javadocs解释这个:

String表示UTF-16格式的字符串,其中补充字符由代理项对表示(有关更多信息,请参阅Character类中的Unicode字符表示forms一节)。 索引值是指char代码单元,因此补充字符在String中使用两个位置。

简而言之,这本书是错误的。

编辑以添加下面的评论:昨晚我没想到的是你在问题中使用的角色实际上并不是他们正在谈论的角色,他们真正得到的是当你有有一个字符需要四个字节而不是两个字节。 Javadoc上面的段落链接到另一个javadoc; Unicode字符表示 ,讨论了这种情况的后果。