必须用 equals() 比较字符串内容,因 == 仅比较内存地址;调用 equals() 前需防 null,推荐用 "literal".equals(str) 或 objects.equals(str1, str2)。

必须用 equals(),不能用 ==;但直接调用仍可能抛 NullPointerException,得防 null。
为什么 == 不能用于字符串内容比较
== 比的是两个变量是否指向同一块内存地址,不是内容。哪怕两个字符串字面量完全一样,只要不是同一个对象,== 就返回 false。
常见错误现象:
-
String a = new String("test"); String b = new String("test"); a == b→false -
String x = "hello"; String y = "hello"; x == y→true(巧合,依赖字符串常量池,不可靠)
本质区别:前者是堆上两个独立对象,后者是常量池中复用的同一引用——但你不该依赖这个行为。
equals() 的安全调用方式
直接写 str1.equals(str2) 有风险:如果 str1 是 null,立刻抛 NullPointerException。
推荐做法(按优先级排序):
- 把字面量放左边:
"expected".equals(input)—— 即使input为null,也安全返回false - 用
Objects.equals(str1, str2)(JDK 7+)——内部已判空,语义清晰 - 避免手写
str1 != null && str1.equals(str2)—— 冗长且易漏掉对str2的容错(其实str2为null是合法的,equals()能正确处理)
忽略大小写的比较:用 equalsIgnoreCase() 而非手动转小写
需要忽略大小写时,别写 str1.toLowerCase().equals(str2.toLowerCase()):
- 创建临时字符串,浪费内存和 GC 压力
- 遇到非 ASCII 字符(如土耳其语
i)时,toLowerCase()行为不一致,结果不可靠
正确做法:str1.equalsIgnoreCase(str2) —— 底层用字符级比较,不生成新对象,且遵循 Unicode 规范。
其他类型或自定义类别误用 equals()
equals() 的行为取决于类是否重写了它:
-
StringBuffer、StringBuilder没重写equals(),调用的是Object版本 → 实际还是比地址,永远false(除非是同一对象) -
Integer、Double等包装类重写了equals(),可安全比值;但new Integer(1) == new Integer(1)仍是false - 自定义类若没重写
equals(),默认行为同==,别想当然认为它能比内容
真正容易被忽略的一点:你写的工具方法里如果接受 Object 类型参数并调用 .equals(),必须确认传入对象所属类是否重写了该方法——否则逻辑就错了。










