Java中的equals与==有什么区别_比较语义解析

equals比较内容是否相等,==比较是否为同一对象;基本类型只能用==,引用类型==比较内存地址,equals默认同==但常用类已重写为逻辑比较,包装类在[-128,127]内==可能为true属JVM实现细节。

Java 中 equals== 的核心区别在于:前者比较“内容是否相等”,后者比较“是否为同一个对象”(即内存地址是否相同)。这个区别看似简单,但实际使用中极易出错,关键要看数据类型和类是否重写了 equals 方法。

基本类型只能用 ==,不能用 equals

int、char、boolean 等 8 种基本数据类型没有方法,也不属于对象,因此不支持调用 equals()。试图对基本类型写 5.equals(5) 会直接编译失败。

它们之间只能用 == 比较值,比如:

  • int a = 10; int b = 10; System.out.println(a == b); // true
  • double x = 3.14; double y = 3.14; System.out.println(x == y); // true

引用类型用 == 比较的是内存地址

String、Integer、ArrayList 等都是引用类型。用 == 判断时,只看两个变量是否指向堆中同一块内存。

常见例子:

  • String s1 = new String("hello");
  • String s2 = new String("hello");
  • System.out.println(s1 == s2); // false —— 两个 new 出来的对象,地址不同
  • String s3 = "world"; String s4 = "world";
  • System.out.println(s3 == s4); // true —— 字符串常量池复用同一对象

equals 默认行为和重写后的语义

equalsObject 类的方法,原始实现就是 return (this == obj);,也就是和 == 效果一样。

但像 StringIntegerLocalDate 等常用类都重写了它,使其按“逻辑内容”比较:

  • "abc".equals("abc") // true —— 比字符序列
  • new Integer(100).equals(100) // true —— 自动拆箱 + 值比较
  • new ArrayList(Arrays.asList(1,2)).equals(Arrays.asList(1,2)) // true —— 比元素顺序和内容

自定义类如不重写 equals,默认仍比较地址;若需按字段判断相等(比如两个 User 对象 id 和 name 都相同即视为相等),必须手动重写 equals(通常也建议同时重写 hashCode)。

包装类的特殊表现:常量池影响 == 结果

Integer、Byte、Character 等部分包装类在 [-128, 127] 范围内会缓存对象(类似字符串常量池):

  • Integer a = 100; Integer b = 100; System.out.println(a == b); // true
  • Integer c = 200; Integer d = 200; System.out.println(c == d); // false(堆中各自 new)
  • 但 c.equals(d) 始终是 true —— 因为 Integer.equals() 比的是 int 值

这种现象不是规范保证的行为,而是 JVM 实现细节,所以永远别依赖 == 来判断包装类值是否相等。