JAVA中对象的几种比较

Java 中对象的几种比较方式(2025-2026 面试高频总结)

在 Java 中,比较两个对象是否“相等”或“大小关系”,主要有以下几种常见方式,每种方式适用的场景和语义完全不同:

比较方式方法/运算符比较内容是否可重写/自定义适用场景是否考虑 null典型实现类示例
引用比较(==)==内存地址是否相同不可判断是否为同一个对象实例所有对象
值相等比较(equals)equals()业务上是否“内容相等”可重写集合判重、Map 键比较、业务相等判断需手动处理String、Integer、自定义实体类
自然顺序比较compareTo()对象之间的自然排序大小可实现 ComparableTreeSet、TreeMap、Collections.sort()需手动处理String、Integer、BigDecimal
自定义比较器Comparator灵活的外部排序规则可新建实例同一类型对象不同场景不同排序规则需手动处理Collections.sort(list, comp)
哈希一致性比较hashCode() + equals()哈希表使用时的快速筛选+精确比较必须同时重写HashMap、HashSet、ConcurrentHashMap需手动处理自定义对象作为 HashMap key 时
深度比较(对象图)Objects.deepEquals()递归比较对象及其引用对象内容单元测试、复杂对象全等判断友好处理测试框架、日志对比
记录类(Record)相等自动生成 equals所有组件字段是否全部相等不可重写值对象、DTO、不可变数据载体友好处理Java 14+ 的 record 类型

详细说明与代码示例

1. 最基础:引用相等(==)

String s1 = new String("hello");
String s2 = new String("hello");

System.out.println(s1 == s2);         // false ← 不同的对象实例
System.out.println(s1 == "hello");    // false ← 常量池与堆对象不同

2. 内容相等(equals)——最常被问的重写规则

class User {
    private Long id;
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id);  // 通常业务上只比 id
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);  // 必须与 equals 保持一致
    }
}

重要原则(面试必背):

  • 自反性:x.equals(x) → true
  • 对称性:x.equals(y) ⇔ y.equals(x)
  • 传递性:x.equals(y) && y.equals(z) → x.equals(z)
  • 一致性:多次调用结果相同(前提对象状态不变)
  • 与 null:x.equals(null) 永远返回 false

3. 自然排序(Comparable)

class Student implements Comparable<Student> {
    String name;
    int age;

    @Override
    public int compareTo(Student o) {
        // 先按年龄升序,年龄相同按姓名降序
        int ageCompare = Integer.compare(this.age, o.age);
        if (ageCompare != 0) return ageCompare;
        return o.name.compareTo(this.name); // 降序
    }
}

4. 自定义比较器(Comparator)——最灵活的方式

// 按姓名长度排序
Comparator<Student> byNameLength = (s1, s2) -> 
    Integer.compare(s1.name.length(), s2.name.length());

// 链式比较(Java 8+)
Comparator<Student> complex = Comparator
    .comparing(Student::getAge)
    .thenComparing(Student::getName, Comparator.reverseOrder());

5. 现代推荐写法(Java 8+ 常用工具类)

// 安全比较(防 NPE)
Objects.equals(obj1, obj2);          // null 安全
Objects.deepEquals(obj1, obj2);      // 深度比较数组、集合等

// 比较大小(防 NPE)
Integer.compare(a, b);               // 代替 a - b(防止溢出)
Long.compare(a, b);

6. 快速决策表(面试/实战常用)

你要做什么?推荐方式备注
判断两个变量是否指向同一个对象==最快
判断两个对象内容是否业务相等equals()最常用
把对象放进 HashMap / HashSet 做 key同时重写 equals + hashCode必须遵守契约
对象需要排序(TreeSet / TreeMap)实现 Comparable 或传 Comparator
同一个类型对象在不同场景需要不同排序规则使用 Comparator推荐
需要比较两个复杂对象是否完全一样(测试)Objects.deepEquals()方便
Java 14+ 值对象、DTO使用 record 类型自动生成完美 equals/hashCode

一句话总结(可直接用于面试结尾):

Java 中对象的比较从最快的 引用比较(==) 到最严格的 业务相等(equals),再到排序用的 Comparable/Comparator,每一种方式都有明确的使用边界和契约。
实际开发中最容易出错的就是 equals 与 hashCode 不配对、或者在可变对象上不当使用它们作为集合 key。

需要我针对某个具体场景再深入讲解吗?
比如:

  • 实体类作为 Map Key 的正确写法
  • record 与普通类的 equals 差异
  • 多字段排序的 10 种写法对比
  • equals 与 == 在各种包装类中的真实表现 等
文章已创建 3771

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部