应使用 equals() 或 charvalue() 比较 character 值;== 比较地址,且 [0,127] 缓存导致行为不一致,易引发隐蔽 bug,超出范围必为 false,编译器禁止直接用关系运算符比较 character 引用。

直接用 == 比较 Character 包装类会出错
Java 中 Character 是引用类型,== 比较的是对象地址,不是字符的 Unicode 值。哪怕两个 Character 包含相同字符(如 'A'),如果它们是不同对象,== 也可能返回 false。
更危险的是:JVM 对 char 值在 [0, 127] 范围内的 Character 实例做了缓存(类似 Integer.valueOf() 的小整数缓存),所以 Character.valueOf('Z') == Character.valueOf('Z') 可能为 true,但换成 '\u0100'(超出缓存范围)就一定为 false——这种行为不一致极易引发隐蔽 bug。
- 不要依赖缓存行为做逻辑判断
- 永远避免用
==比较两个Character的“值相等性” - 关系运算符(
、<code>>、、<code>>=)本身不能直接用于Character引用,会编译报错:bad operand types for binary operator '
正确做法:先拆箱再比较
必须显式将 Character 转为基本类型 char,才能使用关系运算符。Java 会自动拆箱(调用 charValue()),但前提是对象非 null。
示例:
Character c1 = 'B';
Character c2 = 'A';
if (c1 > c2) { // ✅ 编译通过,自动拆箱为 char 后比较 Unicode 值(66 > 65)
System.out.println("c1 的编码更大");
}
注意以下风险点:
- 如果任一
Character为null,运行时抛NullPointerException - 拆箱本质是调用
c1.charValue() > c2.charValue(),比较的是 UTF-16 代码单元值(对 BMP 字符即 Unicode 码点;对增补字符需额外处理) - 若需严格按 Unicode 码点排序(比如含 emoji),应转为
int码点:Character.codePointAt(new char[]{c1}, 0)
需要空安全时用 Character.compare()
当输入可能为 null(如从集合或 API 获取),手动判空再拆箱太啰嗦。推荐使用静态方法 Character.compare(),它接受两个 Character 引用,内部处理 null 并返回 int 比较结果(类似 Integer.compare())。
示例:
Character c1 = null; Character c2 = 'a'; int result = Character.compare(c1, c2); // ✅ 返回 -1(null 视为最小值) if (result
-
Character.compare(c1, c2)返回负数 / 0 / 正数,对应c1 / <code>==/> - 它不支持链式关系表达式(如不能写
c1 ),只能用于条件分支或排序逻辑 - 底层仍是基于
char值比较,不处理代理对
和字符串比较混淆的典型错误
有人误以为 Character 比较和 String.compareTo() 类似,试图调用 compareTo() 方法后再用关系运算符判断返回值——这虽然可行,但绕远且易错:
Character c1 = 'x'; Character c2 = 'y'; if (c1.compareTo(c2) <p>相比直接 <code>c1 ,这种写法:</code></p>
- 性能略差(多了虚方法调用和装箱/拆箱开销)
- 可读性反而下降(
compareTo()返回值需查文档理解含义) - 仍无法规避
null导致的NullPointerException
真正需要抽象比较逻辑(如传入 Comparator<character></character>)时,才考虑 Character::compareTo 或 Character::compare。
最常被忽略的是:关系运算符比较的只是单个 char 的 UTF-16 值,而人类认知的“字符大小”可能涉及语言环境(如德语中 ä 排在 a 之后)。真有本地化需求,必须用 Collator,而不是靠 或 <code>Character.compare()。











