JAVA中对象的几种比较

在Java中,对象的比较主要有以下几种常见方式,它们目的和使用场景完全不同。下面按实际开发中出现频率从高到低整理,并说明区别和注意事项。

1. == 运算符(最基础、最快,但最局限)

Student s1 = new Student("张三", 18);
Student s2 = s1;           // 指向同一对象
Student s3 = new Student("张三", 18);  // 内容相同但不同对象

System.out.println(s1 == s2);   // true   ← 同一个引用
System.out.println(s1 == s3);   // false  ← 不同对象,即使内容完全一样

适用场景

  • 判断两个引用是否指向堆中同一个对象
  • 基本类型的比较(int、double、char等)
  • 单例模式判断、null判断等

永远不要用 == 来比较字符串内容、自定义对象内容(除非你明确就是要比较引用)。

2. equals() 方法(最常用,用于“逻辑相等”比较)

// 默认(Object提供的实现)
public boolean equals(Object obj) {
    return (this == obj);
}

// 几乎所有自定义类都应该重写
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Person person = (Person) o;
    return age == person.age &&
           Objects.equals(name, person.name) &&
           Objects.equals(idCard, person.idCard);
}

最推荐的现代写法(使用Objects工具类)

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Person that)) return false;

    return age == that.age &&
           Objects.equals(name, that.name) &&
           Objects.equals(idCard, that.idCard);
}

常与 hashCode() 一起重写(契约关系):

如果两个对象 equals() 相等,则它们的 hashCode() 必须相等
反过来不一定成立(hashCode相等不代表equals一定相等)

@Override
public int hashCode() {
    return Objects.hash(name, age, idCard);
}

使用场景(非常多):

  • HashMap / HashSet 的 key 判断
  • 对象内容比较(最常见需求)
  • Stream distinct()、contains() 等
  • 业务上认为“逻辑相等”的判断

3. Comparable 接口 → compareTo() 方法(自然排序)

public class Person implements Comparable<Person> {
    private String name;
    private int age;

    @Override
    public int compareTo(Person o) {
        // 先按年龄升序,年龄相同再按姓名字典序
        int ageCompare = Integer.compare(this.age, o.age);
        if (ageCompare != 0) {
            return ageCompare;
        }
        return String.CASE_INSENSITIVE_ORDER.compare(this.name, o.name);
        // 或:return this.name.compareTo(o.name);
    }
}

使用场景

  • TreeSet、TreeMap 的默认排序
  • Collections.sort(list) / Arrays.sort()(当没传Comparator时)
  • 优先级队列(PriorityQueue)默认排序
  • 实体类有“唯一自然顺序”时(如按id、按分数、按时间等)

4. Comparator 接口 → compare() 方法(灵活比较器)

// 方式1:匿名内部类 / lambda
List<Person> list = ...
list.sort((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()));

// 方式2:单独定义比较器(最推荐可复用)
public class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return Integer.compare(p1.getAge(), p2.getAge());
    }
}

// 方式3:多字段组合(非常实用)
Comparator<Person> comparator = Comparator
    .comparingInt(Person::getAge)
    .thenComparing(Person::getName, String.CASE_INSENSITIVE_ORDER);

使用场景(频率非常高):

  • 需要多种排序方式(按年龄、按姓名、按薪资等多种维度)
  • 第三方类不能改(无法实现Comparable)
  • Stream sorted() 排序
  • TreeSet / TreeMap 自定义排序规则
  • 分页查询多字段排序

快速对比表格

比较方式比较内容是否修改类本身主要使用场景是否需要同时重写hashCode典型类/接口
==引用地址判断是否同一对象、null判断
equals()内容(逻辑相等)是(几乎必重写)HashMap key、业务相等判断Object
compareTo()大小/顺序自然排序、TreeSet默认规则Comparable
compare()大小/顺序灵活/多规则排序、第三方类排序Comparator

总结口诀(开发中最常记的)

  1. 想比较是不是同一个对象 → 用 ==
  2. 想比较内容是否逻辑相等 → 重写 equals() + hashCode()
  3. 对象有唯一自然顺序 → 实现 Comparable,重写 compareTo()
  4. 需要多种排序方式不能改类 → 创建 Comparator(lambda最方便)

希望这个总结能帮你快速理清Java对象比较的几种方式和适用场景!如果有具体场景(比如实体类、TreeSet排序、去重等),可以继续告诉我,我可以给出更针对性的代码示例。

文章已创建 4915

发表回复

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

相关文章

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

返回顶部