根据Java SE 7 Specification,Java使用Unicode UTF-16标准来表示字符。
当想象String
作为16位变量的简单数组时,每个变量包含一个字符,生活很简单。
不幸的是,有些代码点只有16位是不够的(我相信它是所有Unicode字符的16/17)。所以在String
中,这没有直接问题,因为当想要使用额外的两个字节存储其中一个~1.048.576个字符时,只需要{{1}中的两个数组位置将被使用。
这不会造成任何直接问题,适用于String
,因为总有两个字节可以使用。虽然单变量与UTF-16编码相比,其固定长度为16位,但如何存储这些字符,特别是Java如何处理它的 2字节“char”类型?
答案 0 :(得分:24)
答案在the javadoc:
char数据类型(因此是Character对象的值 encapsulates)基于原始的Unicode规范 将字符定义为固定宽度的16位实体。 Unicode 从那时起,标准被改为允许其角色 表示需要超过16位。
法律代码的范围 点现在是U + 0000到U + 10FFFF,称为Unicode标量值。 (请参阅Unicode标准中U + n表示法的定义。) 有时会引用从U + 0000到U + FFFF的字符集 作为基本多语言平面(BMP)。代码指向的字符 大于U + FFFF被称为补充字符。 Java 2平台使用char数组和中的UTF-16表示 String和StringBuffer类。在此表示中,补充 字符表示为一对char值,第一个来自 高代理范围,(\ uD800- \ uDBFF),第二个来自 低代理范围(\ uDC00- \ uDFFF)。
因此,char值 表示基本多语言平面(BMP)代码点,包括 代理代码点,或UTF-16编码的代码单元。一个int value表示所有Unicode代码点,包括补充代码 点。 int的较低(最低有效)21位用于 表示Unicode代码点和上(最重要)11位 必须为零。
除非另有说明,否则相关的行为 补充字符和代理字符值如下: 只接受char值的方法不能支持补充 字符。他们将代理范围中的char值视为 未定义的字符。例如,Character.isLetter('\ uD840') 返回false,即使此特定值后跟any 字符串中的低代理值表示字母。方法 接受int值支持所有Unicode字符,包括 补充字符。例如,Character.isLetter(0x2F81A) 返回true,因为代码点值表示一个字母(一个CJK 表意文字)。在Java SE API文档中,Unicode代码点是 用于U + 0000和U + 10FFFF之间范围内的字符值, 和Unicode代码单元用于代码的16位字符值 UTF-16编码的单位。有关Unicode的更多信息 术语,请参阅Unicode词汇表。
简单地说:
更简单的说:
顺便说一下,可以注意到Unicode扩展到BMP之后使得UTF-16全局无关,现在UTF-16甚至没有启用固定的字节字符比。这就是更多现代语言基于UTF-8的原因。这manifesto有助于理解它。
答案 1 :(得分:7)
基本上,字符串存储一系列UTF-16代码单元......这与存储Unicode代码点序列不同。
当需要基本多语种平面之外的字符时,它会占用String
内的两个UTF-16代码单元。
大多数String
操作 - length()
,charAt
,substring()
等处理UTF-16代码单元的数量。但是,有codePointAt()
之类的操作将处理完整的Unicode代码点......尽管索引仍以UTF-16代码单位表示。
编辑:如果你想在一个char
中存储一个非BMP代码点,你基本上就不走运了。这就像是想在byte
变量中存储超过256个不同的值......它只是不起作用。遵循在其他地方表示代码点的约定(例如在String
中),最好只使用int
变量。