“equal”、“==” 和 “hashCode” 的区别和使用场景?

本文详细介绍了Java中equals()和hashCode()方法的作用和使用场景。equals()方法用于比较对象的内容是否相等,而hashCode()则是为了提高查找效率,通常与HashSet等数据结构配合使用。当重写equals()时,应同时重写hashCode()以保持一致性。如果两个对象equals()返回true,那么它们的hashCode()必须相同;反之,hashCode()相同并不意味着equals()也相等。此外,不正确的重写可能导致HashSet等数据结构性能下降。

点击“开发者技术前线”,选择“星标”

让一部分开发者先看到未来

回复“666”,获取一份专属大礼包

==

用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据(注意是基本类型)或两个 引用变量是否相等,只能用==操作符。
假如一个变量指向的数据是对象类型的,例如Objet obj 1= new Object() 那么,这时候涉及了两块内存;变量 obj1 是一个内存,new Object() 是另一个内存(堆内存),此时,变量 obj1 所对应的内存中存储的数值就是对象占用的那块内存(堆内存)的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较;

hashcode()

  1. hashCode 的存在主要用于查找的快捷性,如 Hashtable, HashMap 等,hashCode 是用来在三列存储结构中确定对象的存储地址的。

  2. 如果两个对象相同,就是适用于 euqals(java.lang.Object) 方法,那么这两个对象的 hashCode一定相同。

  3. 如果对象的euqals 方法被重写,那么对象的 hashCode 也尽量重写,并且产生 hashCode 使用的对象,一定要和 equals 方法中使用的一致,否则就会违反上面提到的第二点。

  4. 两个对象的 hashCode 相同,并不一定表示这两个对象就相同,也就是不一定适用于equals() 方法,只能够说明这两个对象在三列存储结构中,如 Hashtable.,他们存在同一个篮子里。
    以上话以前摘录自一篇博客,讲的非常好。

equals(Object obj)

  1. 如果一个类没有重写 equals(Object obj)方法,则等价于通过 == 比较两个对象,即比较的是对象在内存中的空间地址是否相等。

  2. 如果重写了equals(Object ibj)方法,则根据重写的方法内容去比较相等,返回 true 则相等,false 则不相等。

我用一个简单的demo来举个例子吧.

public class MyClass {
 public static void main(String[] args) {
     HashSet books=new HashSet();
     books.add(new A());
     books.add(new A());
     books.add(new B());
     books.add(new B());
     books.add(new C());
     books.add(new C());
     System.out.println(books);
 }
}
class A{
 //类A的 equals 方法总是返回true,但没有重写其hashCode() 方法
 @Override
 public boolean equals(Object o) {
     return true;
 }
}
class B{
 //类B 的hashCode() 方法总是返回1,但没有重写其equals()方法
 @Override
 public int hashCode() {
     return 1;
 }
}
class C{
 public int hashCode(){
     return 2;
 }


 @Override
 public boolean equals(Object o) {
     return true;
 }
}

结果

  1. 即使两个A 对象通过 equals() 比较返回true,但HashSet 依然把他们当成 两个对象,即使两个 B 对象 的hashCode() 返回值相同,但HashSet 依然把他们当成两个对象。

  2. 即也就是,当把一个对象放入HashSet 中时,如果需要重写该对象对应类的 equals() 方法,则也应该重写其 hashCode() 方法。规则是:如果两个对象通过 equals() 方法比较返回true,这两个对象的 hashCode 值也应该相同。

  3. 如果两个对象通过euqals() 方法比较返回true,但这两个对象的 hashCode() 方法返回不同的hashCode 值时,这将导致HashSet 会把这两个对象保存在 Hash 表的不同位置,从而使两个对象都可以添加成功,这就与 Set 集合的规则冲突了。

  4. 如果两个对象的 hashCode() 方法返回的 hasCode 值相同,但他们通过 equals() 方法比较返回false 时将更麻烦:因为两个对象的hashCode 值相同,HashSet 将试图 把它们保存在同一个位置,但又不行(否则将只剩下一个对象),所以实际上会在这个位置用链式结构来保存多个对象;而HashSet 访问集合元素时也是根据元素的 hashCode 值来快速定位的,如果 hashSet 中两个以上的元素具有相同的 HashCode 值时,将会导致性能下降。

  • equals:
    equals 方法是用于比较两个独立对象的内容是否相同:

    String a=new String("a");
    String b=new String("a");

    两条new语句创建了两个对象,然后用a/b这两个变量分别指向了其中一个对象,这是两个不同的对象,它们的首地址是不同的,即a和b中存储的数值(对应对象的首地址)是不相同的,所以,表达式a==b将返回false,而这两个对象中的内容是相同的,所以,表达式a.equals(b)将返回true。我们看看equal 源码:

    如果一个类没有重写equals 方法 那么就是调用 object 的 equals 其实就是 ==

  •  * Note that it is generally necessary to override the {@code hashCode}
     * method whenever this method is overridden, so as to maintain the
     * general contract for the {@code hashCode} method, which states
     * that equal objects must have equal hash codes.
     *
     * @param   obj   the reference object with which to compare.
     * @return  {@code true} if this object is the same as the obj
     *          argument; {@code false} otherwise.
     * @see     #hashCode()
     * @see     java.util.HashMap
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }
    
  • hashCode:
    因为重写的 equals() 里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个 hash 值进行比较就可以了,效率很高,那么 hashCode() 既然效率这么高为什么还要 equals() 呢?

  • 使用场景:
    因为 hashCode() 并不是完全可靠,有时候不同的对象他们生成的 hashcode 也会一样(hash冲突),所以 hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以可以得出:
    equals() 相等的两个对象他们的 hashCode() 肯定相等,也就是用 equals() 对比是绝对可靠的。
    hashCode() 相等的两个对象他们的 equals() 不一定相等,也就是 hashCode() 不是绝对可靠的。
    所有对于需要大量并且快速的对比的话如果都用 equals() 去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用 hashCode() 去对比,如果 hashCode() 不一样,则表示这两个对象肯定不相等(也就是不必再用 equals() 去再对比了),如果 hashCode() 相同,此时再对比他们的 equals(),如果 equals() 也相同,则表示这两个对象是真的相同了

 写在最后:

 最近大厂经常会考八股文,所以给读者整理了一份大厂面试真题,需要的可扫码回复“大厂面试”获取。

END

好文点个在看吧!

<think>好的,我现在要帮助用户理解Java中“==”equals方法的区别。首先,我需要回忆一下自己之前学过的相关知识,并结合提供的引用内容来整理答案。 根据引用内容,“==”是一个操作符,用于比较基本数据类型的值或对象的引用地址。而equals方法用于比较对象的内容,但默认情况下(如果没有被重写)它“==”一样比较引用地址。很多类如String、Integer等重写了equals方法,使其比较内容。 首先,我需要明确两者的基本区别。比如,对于基本数据类型,只能用“==”比较值,而对象的话,“==”比较内存地址,equals比较内容(如果重写过的话)。这时候需要举例子,比如字符串的例子,用户可能容易混淆的情况,比如使用new创建的两个String对象,用“==”比较是false,而equals是true,而字符串常量池中的情况又不同。 然后,要分点说明,可能需要从类型、比较内容、适用范围等方面对比。同时,需要注意默认的equals方法行为重写后的不同。比如Object类的equals方法默认“==”一样,但子类可以重写。例如String类就重写了,所以比较内容。 还要提到性能方面,“==”比较快,因为它只是比较引用或值,而equals可能需要更多的计算,特别是当对象比较复杂时。引用[4]中提到这一点。 可能还需要讨论一些常见误区,比如自动装箱的情况,或者像Integer缓存的情况,比如Integer a = 127Integer b = 127,用“==”比较可能是true,但超过缓存范围后就是false了。不过这个例子是否在提供的引用中提到呢?引用[4]中提到了Integer的例子,但用的是250,所以缓存范围之外的,所以c == d是false。这个可以作为例子说明。 此外,需要强调重写equals方法的重要性,比如在自定义类中,如果需要比较对象的内容,必须重写equalshashCode方法,否则默认的equals只是比较地址。引用[2]中的Person类例子就说明了这一点。 接下来,用户的问题可能还会涉及到如何正确重写equals方法,但根据用户的问题,他们可能只需要区别,所以这部分可能放在相关问题里。 现在,需要确保回答结构清晰,分点说明两者的区别,并给出示例代码,帮助用户理解。例如,引用中的示例代码展示了字符串自定义对象的比较情况,可以用来举例。 最后,根据用户要求,生成相关问题,可能涉及性能、重写方法、应用场景等。 检查是否有遗漏点,比如基本数据类型引用类型的区别,以及自动装箱的情况是否需要提及。根据提供的引用,引用[2][4]中提到了基本数据类型的比较,所以需要明确说明。 总结步骤: 1. 定义“==”equals的基本区别,类型(操作符vs方法)、比较内容(值/地址vs内容)、适用范围。 2. 分点详细说明两者的行为,包括默认重写后的情况。 3. 提供示例代码,比如字符串比较自定义对象比较。 4. 强调重写equals的重要性。 5. 性能比较(引用[4]提到的)。 6. 生成相关问题。 需要确保LaTeX格式正确,比如变量用$...$,如$42 == 42.0$是否正确?在中文回答中是否需要处理?根据系统指令,行内数学表达式用$...$,但这里的示例中的代码变量可能不需要,但用户的问题中没有数学公式,可能不需要处理。但根据示例,可能代码块需要正确展示。 现在,开始组织回答内容,确保结构清晰,符合用户要求。</think>### Java中"=="equals方法的区别 #### 1. 核心区别概述 - **`==`操作符**:比较基本数据类型的**值**或对象的**内存地址**。 - **`equals()`方法**:默认比较对象的**内存地址**,但可通过重写实现**内容比较**(如String、Integer等类已重写)。 #### 2. 详细对比 | 对比项 | `==`操作符 | `equals()`方法 | |---------------|------------------------------------|------------------------------------| | **类型** | 操作符 | Object类方法 | | **比较内容** | 基本类型:值;对象类型:内存地址 | 默认比较内存地址,重写后比较内容 | | **适用范围** | 基本类型对象类型均可使用 | 仅适用于对象类型 | | **性能** | 更快(直接比较值或地址)[^4] | 较慢(可能涉及字段遍历) | #### 3. 示例说明 ##### 基本数据类型比较 ```java int a = 100; int b = 100; System.out.println(a == b); // 输出true,比较值 ``` ##### 对象类型比较 ```java String str1 = new String("hello"); String str2 = new String("hello"); System.out.println(str1 == str2); // false,内存地址不同 System.out.println(str1.equals(str2)); // true,内容相同(String重写了equals) ``` ##### 自定义对象比较 ```java class Person { String name; int age; // 需重写equals方法 @Override public boolean equals(Object obj) { if (obj instanceof Person) { Person p = (Person) obj; return this.name.equals(p.name) && this.age == p.age; } return false; } } Person p1 = new Person("Alice", 30); Person p2 = new Person("Alice", 30); System.out.println(p1 == p2); // false,内存地址不同 System.out.println(p1.equals(p2)); // true,内容相同
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值