Character自动装箱仅缓存U+0000至U+007F(0–127)字符,超出范围每次新建对象,故比较必须用equals()而非==。

Java 中自动装箱与拆箱对 Character 类的处理,核心在于范围限制与缓存机制——它不像 Integer 那样有 -128 到 127 的默认缓存区间,而是只缓存 0 到 127(即 U+0000 到 U+007F)的 Latin-1 字符。超出这个范围的字符,每次装箱都会新建对象,可能引发意料之外的引用比较问题。
Character 的自动装箱实际调用的是 valueOf(char)
当你写:
Character c1 = 'A'; // 自动装箱 Character c2 = 'A'; System.out.println(c1 == c2); // true
编译器实际执行的是:
Character c1 = Character.valueOf('A');
Character c2 = Character.valueOf('A');Character.valueOf(char) 内部做了缓存优化:
立即学习“Java免费学习笔记(深入)”;
- 若
ch在[0, 127]范围内,返回静态缓存数组中的同一个Character实例; - 若
ch > 127(比如'α'、'中'、'?'),则每次调用都new Character(ch),返回新对象。
常见陷阱:== 比较失效
Character a = '\u007F'; // 127,缓存内 Character b = '\u007F'; System.out.println(a == b); // true Character c = '\u0080'; // 128,超出缓存 Character d = '\u0080'; System.out.println(c == d); // false!不是同一个对象
所以判断相等必须用 .equals():
System.out.println(c.equals(d)); // true ✅
为什么只缓存 0–127?
这是 Java 规范明确规定的(JLS §5.1.7):
Character.valueOf(char)方法必须缓存'\u0000'到'\u007F'(含)共 128 个字符;对其他字符,缓存行为不作要求。
这个范围覆盖了 ASCII 和基本 Latin-1 字符,兼顾性能与内存开销。Unicode 中文、emoji、扩展符号都不在此列。
实际编码建议
- 永远避免用
==比较两个Character对象,除非你100% 确认它们都在 0–127 范围且来自自动装箱 - 需要判等时统一用
.equals() - 集合(如
Set<Character>、Map<Character, ?>)中使用Character安全,因为集合内部调用的是equals()和hashCode() - 如果频繁处理高码点字符(如解析 JSON、处理多语言文本),不必担心装箱性能——
Character对象本身很轻量,但要注意对象复用率低,GC 压力略高于小范围场景
font color="gray">注意:从 Java 9 起,new Character(ch) 构造方法已被标记为 @Deprecated,应完全依赖 valueOf() 或自动装箱


















