equals、==、hashCode的区别、为什么要重写HashCode方法?

一:equals

equals用来比较的是两个对象的内容是否相等(即比较内存地址是否相同),由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象。

二:==

如果是基本类型比较的是数值大小;
如果是引用类型比较的是内存地址;

== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。

1、比较的是操作符两端的操作数是否是同一个对象。
2、两边的操作数必须是同一类型的(可以是父子类之间)才能编译通过。
3、比较的是地址,如果是具体的阿拉伯数字的比较,值相等则为true,如:
int a=110 与 long b=110L 与 double c=110.0都是相同的(为true),因为他们都指向地址为110的堆。

代码验证实例:

public class Test {
    public static void main(String[] args) {
        String a = new String("abc"); // a 为一个引用
        String b = new String("abc"); // b为另一个引用,对象的内容一样
        String aa = "abc"; // 放在常量池中
        String bb = "abc"; // 从常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一对象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("a EQ b");
        if (142 == 142.1) { // true
            System.out.println("true");
        }
    }
}

PS:这里记录生产系统一个bug,就是用错了!= 导致出了系统问题

			String version = doc.get("FormVersion").toString();
			if(version  != "5"){
				drawingType = doc.get("DrawingType").toString();
				if(!"1".equals(drawingType)){
					.......
				}
			}

doc.get(“FormVersion”).toString()本身值为5,但是doc.get(“FormVersion”).toString() != "5"结果确为true,因为string类型已经对结果进行了Boolean判断,所以导致!=判断失效。
如果比较判断数值大小,这里要用equals!

代码分析

import java.util.HashSet;
import java.util.Set;

public class Test2 {
    public static void main(String[] args) {
        String s1 = new String("123");
        String s2 = new String("123");
        System.out.println(s1 == s2);//false
        System.out.println(s1.equals(s2));//true

        Set set1 = new HashSet();
        set1.add(s1);
        set1.add(s2);
        System.out.println(s1.hashCode()+"\t"+s2.hashCode());
        System.out.println(set1.size());//1
        System.out.println("**************************************************");
        Person p1 = new Person("zhangsanfeng");
        Person p2 = new Person("zhangsanfeng");
        System.out.println(p1 == p2);//false
        System.out.println(p1.equals(p2));//false
        Set set2 = new HashSet();
        set2.add(p1);
        set2.add(p2);
        System.out.println(p1.hashCode()+"\t"+p2.hashCode());
        System.out.println(set2.size());//2
    }
}

执行结果
equals、==、hashCode的区别、为什么要重写HashCode方法?_第1张图片
结果分析
(1)String类对equals进行了重写,所以对于String类型其equals比较的是内容而不是引用地址,所以是true。而Person类属于自定义类并没有对equals进行重写,则比较的是引用地址,所以是false。
equals、==、hashCode的区别、为什么要重写HashCode方法?_第2张图片
String重写hashcode方法,其比较的是值
equals、==、hashCode的区别、为什么要重写HashCode方法?_第3张图片

(2)HashSet底层采用HashMap进行存储
equals、==、hashCode的区别、为什么要重写HashCode方法?_第4张图片
HashSet的add方法,value值存储的是一个Object类型常量。底层是调用HashMap的put方法。
equals、==、hashCode的区别、为什么要重写HashCode方法?_第5张图片
而Person类其用的是Object原生的hashcode方法,则结果不一样,所以size()为2。

三:hashCode

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
1)、如果两个对象相等,那么它们的hashCode()值一定相同。
这里的相等是指,通过equals()比较两个对象时返回true。
2)、如果两个对象hashCode()相等,它们并不一定相等。
因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出键值对相等。补充说一句:“两个不同的键值对,哈希值相等”,这就是哈希冲突。

此外,在这种情况下。若要判断两个对象是否相等,除了要覆盖equals()之外,也要覆盖hashCode()函数。否则,equals()无效。

四:为什么需要重写equals?

当我们的对象之间是否相等需要根据对象的内容判断而不是通过对象存储的地址判断的时候我们就需要重写equals。
比如有一个用户类(User),里面有用户编号的属性,不管这个对象是根据什么情况创建出来的,只要他们的编号相同,我们就认为他们是相等的,这个时候就要重写equals。

五::为什么在重写equals方法的时候要重写hashcode的方法?

判断的时候先根据hashcode进行的判断,相同的情况下再根据equals()方法进行判断。如果只重写了equals方法,而不重写hashcode的方法,会造成hashcode的值不同,而equals()方法判断出来的结果为true。

在Java中的一些容器中,不允许有两个完全相同的对象,插入的时候,如果判断相同则会进行覆盖。这时候如果只重写了equals()的方法,而不重写hashcode的方法,Object中hashcode是根据对象的存储地址转换而形成的一个哈希值。这时候就有可能因为没有重写hashcode方法,造成相同的对象散列到不同的位置而造成对象的不能覆盖的问题。

参考文章
https://blog.csdn.net/qq_28051453/article/details/52701171
https://blog.csdn.net/sssdal19995/article/details/105622577

你可能感兴趣的:(Java,java)