你还在傻傻的背八股文吗?

思维导图:

你还在傻傻的背八股文吗?_第1张图片

==和equals都是Java中判断两个变量是否相等的方式。他们具有如下区别:

1. 所属类别与本质

== 是 运算符,可用于比较基本数据类型和引用数据类型。equals() 是 Object 类的方法,只能用于比较引用数据类型(对象),基本数据类型无此方法。

2.比较规则不同

2.1对于基本数据类型来说

== 直接比较值是否相等,equals() 无法用于基本数据类型,因为它是对象方法,基本类型没有此方法。

2.2对于引用数据类型来说:

== 比较 对象的内存地址 是否相同(即是否指向同一个对象)。equals():若未重写,默认与 == 行为一致(比较内存地址)。若重写(如 StringInteger 等类)equals(),则按重写逻辑比较对象内容

代码示例:

public boolean equals(Object obj) {
    return (this == obj);   //默认比较内存地址
}
public class EqualsMethodExample {
    public static void main(String[] args) {
        String str1 = new String("hello");
        String str2 = new String("hello");
        System.out.println(str1.equals(str2)); // 输出: true,因为 String 类重写了 equals() 方法,比较的是字符串内容

        Object obj1 = new Object();
        Object obj2 = new Object();
        System.out.println(obj1.equals(obj2)); // 输出: false,因为使用的是 Object 类的默认 equals() 方法,比较的是内存地址
    }
}

3. 常见场景

  • 比较基本数据类型的值,用 ==
  • 比较对象是否为同一实例(地址相同),用 ==
  • 比较对象内容是否相等(类重写了 equals()),用 equals()。例如判断两个 String 内容是否相同、两个自定义对象的属性是否一致等。

4.总结对比表

特性 == 运算符 equals() 方法
所属类型 运算符 Object 类的方法
基本类型比较 比较值是否相等 不可用(仅用于对象)
引用类型比较 比较内存地址是否相同 未重写时比地址,重写后按逻辑比内容
能否重写 不能(运算符无法重载) 可以(根据业务需求自定义比较逻辑)

5.重写 equals() 方法的步骤

  1. 检查引用是否相同:使用 == 运算符检查两个引用是否指向同一个对象,如果是则直接返回 true
  2. 检查对象是否为 null:检查传入的对象是否为 null,如果是则返回 false
  3. 检查对象类型是否相同:使用 instanceof 运算符检查传入的对象是否为当前类或其子类的实例,如果不是则返回 false
  4. 强制类型转换:将传入的对象强制转换为当前类的类型。
  5. 比较对象的属性:比较当前对象和传入对象的关键属性是否相等。

代码示例:

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 重写 equals() 方法
    @Override
    public boolean equals(Object obj) {
        // 检查引用是否相同
        if (this == obj) {
            return true;
        }
        // 检查对象是否为 null
        if (obj == null) {
            return false;
        }
        // 检查对象类型是否相同
        if (!(obj instanceof Person)) {
            return false;
        }
        // 强制类型转换
        Person other = (Person) obj;
        // 比较对象的属性
        return this.name.equals(other.name) && this.age == other.age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("Alice", 25);
        Person person2 = new Person("Alice", 25);
        Person person3 = new Person("Bob", 30);

        System.out.println(person1.equals(person2)); // 输出: true
        System.out.println(person1.equals(person3)); // 输出: false
    }
}

 但需要注意的是,在重写equals()时,一般也要重写hashcode(),那这是为什么呢?

6.为什么重写equals()时,一般也要重写hashcode()

一、Java 对象相等判断的约定


根据 Java规范,equals() 和 hashCode() 需满足以下关系:

1.若两个对象 equals() 返回 true,它们的 hashCode() 必须相同。
2.若两个对象 hashCode() 不同,equals() 必须返回 false。

这是为了确保对象在哈希表(如 HashSet、HashMap)中行为的一致性。若只重写 equals() 而不重写 hashCode(),可能出现两个 equals() 相等的对象 hashCode() 不同导致哈希表无法正确识别重复元素或键,破坏数据结构的逻辑。

二、哈希表的底层原理


哈希表(如 HashMap、HashSet)通过 “先比较 hashCode,再比较 equals” 来提升效率:


1.定位存储位置:先通过 hashCode() 计算哈希值,确定对象在哈希表中的桶(数组下标)。若 hashCode 不同,直接判定对象不等,无需调用 equals(),减少比较次数。


精确判断相等:若 hashCode 相同,再通过 equals() 确认对象内容是否真正相等。
若只重写 equals(),未重写 hashCode(),则默认 hashCode() 基于对象内存地址计算。此时两个 equals() 相等的对象(如自定义类的两个实例,内容相同但内存地址不同),hashCode() 可能不同,
导致:在 HashSet 中被视为不同元素,无法正确去重。在 HashMap 中被存储到不同桶位,无法通过键正确获取值,破坏数据一致性。

代码示例:

假设自定义类 Person只重写 equals(),未重写 hashCode()

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return name.equals(person.name) && age == person.age;
    }
}

当将两个内容相等的 Person 对象存入 HashSet 时:

HashSet set = new HashSet<>();
Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);
set.add(p1);
set.add(p2);
System.out.println(set.size()); // 输出 2,本应去重但未实现

由于未重写 hashCode()p1 和 p2 的 hashCode 不同(基于内存地址),HashSet 认为它们是不同元素。若同时重写 hashCode()

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return name.equals(person.name) && age == person.age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age); // 根据内容计算 hashCode
    }
}

 解释说明:此时 p1 和 p2 的 hashCode 相同,HashSet 会通过 equals() 确认相等,正确去重,set.size() 输出 1

总结:

  • 重写 equals() 时必须重写 hashCode(),本质是为了:遵循 Java 规范,确保对象相等判断逻辑的一致性。
  • 保证哈希表等数据结构正常工作,避免因 hashCode 不一致导致的去重失败、键值对存储 / 查询错误等问题。
  • 优化比较效率,利用 hashCode 快速过滤不等对象,减少 equals() 调用次数。

因此,在涉及对象比较或使用哈希表相关集合时,两者必须同时重写,且基于相同的属性逻辑,以保证程序的正确性和性能。

你可能感兴趣的:(Java面试合集,java,开发语言,面试)