概述
Java中String的设计是在Unicode编码尚未完成时进行的,原本用来表示世界上所有字符的16个位在后期不能胜任这个任务。Java使用了一种可变长的,向后兼容的编码,UTF-16。
- 典型的(可以在16位以内表示的字符)用一个16位编码来表示,占用一个char;
- 占用位数超过16位的字符用一组(几个)来自编码空间中特殊区域的16位编码(称作surrogate characters)来表示,占用多个char;
能表示一个字符的16位的(一个char)或n*16位(多个char)的编码称作码点,每个16位编码(每个char)称作码元。
这里需要了解一点 utf-16 的东西,即如何区分一个和两个码元组成的码点。
直接上结论:
在 utf-16 中,从 U+D800 到 U+DFFF 之间的码位区段是永久保留不映射到Unicode字符,即当一个码点只占用一个码元时,0xD800 到 0xDFFF 是不使用的。反之,如果遇到一个码元在这个区间中,那么这个码元一定和下一个码元一起组成一个码点。
具体的编码方式可以参考:
Unicode中UTF-8与UTF-16编码详解 - 掘金
本文通过介绍Unicode编码以及对应的两种编码方式UTF-8和UTF-16,让读者能够了解关于字符串编码的相关知识,同时能够弄清楚Unicode和UTF-8和UTF-16之间的关系。 本文作为utfx.js源码解析的基础知识储备文章,通过了解UTF-8和UTF-16这两种编码…

https://zh.m.wikipedia.org/wiki/UTF-16
实验
输出每个码元(code unit)
String str = " ";
System.out.println(str.length());
for(char e : str.toCharArray()){
System.out.print(e+": ");
System.out.printf("\\u%04x\n", (inte);
}
这段代码的输出是
2
?: \ud835
?: \udd46
输出每个码点(code point)
int i = 0;
while (i < str.length()) {
int j = str.offsetByCodePoints(i, 1); //j will be 2, offset 1 codepoint of( ) is 2 codeunit(2 char)
String codePoint = str.substring(i, j);
System.out.println(codePoint);
i = j;
}
完整代码
public class CodePointTest {
public static void main(String[] args) {
String str = " ";
System.out.println(str.length());
for (char e : str.toCharArray()) {
System.out.print(e + ": ");
System.out.printf("\\u%04x\n", (int) e);
}
int i = 0;
while (i < str.length()) {
int j = str.offsetByCodePoints(i, 1); //j will be 2, offset 1 codepoint of( ) is 2 codeunit(2 char)
String codePoint = str.substring(i, j);
System.out.println(codePoint);
i = j;
}
}
}