Java 语言规范规定,Java 内部使用 Unicode 字符集。在不同的层面(源码、编译后的 Class 文件、运行时内存),Java 对 Unicode 的存储方式有一些特定的设计和演进。
以下是 Java 存储 Unicode 的核心机制:
char 与 UTF-16在 Java 中,基本字符类型 char 固定占用 16 位(2 字节),它采用的是 UTF-16 编码的一个“代码单元(Code Unit)”。
char 就可以存储一个常用字符。Unicode 中还有一些字符位于“补充平面”(如部分生僻汉字、Emoji 表情等,码点大于 U+FFFF)。由于 16 位空间不够,Java 采用了 UTF-16 的**代理对(Surrogate Pair)**机制:
char(共 4 字节)来组合表示一个补充平面的 Unicode 码点(Code Point)。char。为了能完整表示任意 Unicode 字符,Java 中通常用 int(32 位)类型来代表一个完整的“码点”(例如在 Character.codePointAt() 等 API 中)。String 在运行时内存中的存储String 是 Java 中使用最频繁的类型,它在内存中的存储方式在 JDK 9 前后发生了重要变化:
String 内部通过一个 char[] 数组存储,不管是什么字符,每个字符都固定占用 2 字节(纯 UTF-16)。这种方式对于纯英文或数字(Latin-1)场景来说非常浪费内存。String 内部改为使用 byte[] 数组,并带有一个编码标记(coder):
String,而是采用“全 Latin-1(定长1字节)”或“全 UTF-16(定长2字节)”的方式,以便于字符的随机访问。.java 源文件:通常我们在磁盘上以 UTF-8 编码保存源文件,源码中可以直接写中文或表情符号(当然也可以使用 \uXXXX 的 Unicode 转义序列)。由于 Java 采用 UTF-16 代码单元(char)作为基础,开发者在处理字符串时需要注意:
String.length() 的陷阱:该方法返回的是 char 的数量(代码单元数),而不是肉眼看到的“字符”数。例如一个 Emoji 表情(代理对)的 length() 会返回 2。string.codePointCount(0, string.length()) 或流式遍历 string.codePoints()。substring() 时要小心,如果截取位置恰好把一个“代理对(如 Emoji)”从中间切断,就会产生乱码(显示为 �)。.getBytes(StandardCharsets.UTF_8)),不要依赖平台默认编码,否则极易导致乱码。总结:Java 在内存中主要用 UTF-16(JDK 9+ 优化为 Latin-1/UTF-16 混合)来存储字符,在 Class 字节码中用 Modified UTF-8 存储,而在外部文件或网络传输时则通常使用标准的 UTF-8 进行编解码。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。