Java - 什么是字符、码位和代理项?它们之间有什么区别?

2022-08-31 22:30:08

我试图找到术语“字符”,“代码点”和“替代”的解释,虽然这些术语不仅限于Java,但如果有任何特定于语言的差异,我希望解释与Java有关。

我发现了一些关于字符和代码点之间差异的信息,字符是为人类用户显示的内容,代码点是编码该特定字符的值,但我对代理项一无所知。什么是代理项,它们与字符和代码点有何不同?我对字符和码位有正确的定义吗?

在另一个关于将字符串作为字符数组单步执行的线程中,提示此问题的特定注释是“请注意,此技术为您提供的是字符,而不是代码点,这意味着您可能会获得代理项。我并没有真正理解,而不是对一个5年前的问题进行一长串的评论,我认为最好在新问题中要求澄清。


答案 1

要在计算机中表示文本,您必须解决两件事:首先,您必须将符号映射到数字,然后,您必须用字节表示这些数字的序列。

码位是标识符号的数字。为符号分配数字的两个众所周知的标准是 ASCII 和 Unicode。ASCII 定义了 128 个符号。Unicode目前定义了109384符号,这比216要多得多。

此外,ASCII 指定数字规则表示每个数字一个字节,而 Unicode 指定几种可能性,例如 UTF-8、UTF-16 和 UTF-32。

当您尝试使用每个字符使用的位数少于表示所有可能值所需的位数的编码时(例如,使用 16 位的 UTF-16),您需要一些解决方法。

因此,代理项是 16 位值,指示不适合单个双字节值的符号。

Java 在内部使用 UTF-16 来表示文本。

特别是,(字符)是包含 UTF-16 值的无符号双字节值。char

如果你想了解更多关于Java和Unicode的信息,我可以推荐这个时事通讯:第1部分第2部分


答案 2

您可以在Javadoc中找到java.lang.Character类的简短说明:

统一码字符表示

数据类型(以及对象封装的值)基于原始 Unicode 规范,该规范将字符定义为固定宽度的 16 位实体。此后,Unicode 标准已更改为允许其表示形式需要超过 16 位的字符。法律码位的范围现在是 到 ,称为 Unicode 标量值。[..]charCharacterU+0000U+10FFFF

从 到 的字符集有时称为基本多语言平面 (BMP)。码位大于的字符称为增补字符。Java 平台在数组和 和 类中使用 UTF-16 表示形式。在此表示形式中,增补字符表示为一对值,第一个值来自高代理项范围 (\uD800-\uDBFF),第二个值来自低代理项范围 (\uDC00-\uDFFF)。U+0000U+FFFFU+FFFFcharStringStringBufferchar

换句话说:

代码点通常表示单个字符。最初,类型的值与 Unicode 码位完全匹配。这种编码也称为 UCS-2char

因此,被定义为 16 位类型。但是,Unicode 中目前有超过 2^16 个字符。为了支持整个字符集,编码从固定长度编码 UCS-2 更改为可变长度编码 UTF-16。在此编码中,每个码位由一个或两个 s 表示。在后一种情况下,这两个字符称为代理项对charcharchar

UTF-16 是这样定义的,即如果所有码位都低于 2^14,则使用 UTF-16 和 UCS-2 编码的文本之间没有区别。这意味着,可用于表示某些但不是全部字符。如果一个字符不能在单个中表示,则该术语具有误导性,因为它仅用作16位单词。charcharchar