1.概念
- ==:操作符,比较两个对象之间的数值关系,返回boolean类型
- equals:Object类的方法,比较两个对象内容关系,返回boolean类型
- hashCode:Object类的方法,返回对象的hash值
2.具体分析
2.1 ==
在java的8种基本数据类型,也即 byte,short,char,int,long,float,double,boolean,等号操作符比较的都是数值的大小比较。引用数据类型比较的是内存地址是否相同。
2.2 equals
public boolean equals(Object obj) {
return (this == obj);
}
通过源码我们可以发现,原来,对于引用数据类型而言,equals和==的作用是一样的,但是,好像两个内容相同的字符串一般的equals方法作比较的时候,明明是不同的对象,也即内存地址不一致,貌似返回true,我们来看String的源码
public boolean equals(Object anObject) {
if (this == anObject) {//判断类型是否一致
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = count;
if (n == anotherString.count) {//判断内容长度是否一致
int i = 0;
while (n-- != 0) {//判断内容是否一致
if (charAt(i) != anotherString.charAt(i))
return false;
i++;
}
return true;
}
}
return false;
}
原来,String的equals的方法进行了重写,也即只要内容一致,就返回true。同时,java中的基本数据类型的包装类型的equals方法也都是进行了重写,判断逻辑和String的重写类似。
同时,在java中,equals重写一般需要满足一下原则:
对称性: 如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true” ;
自反性: x.equals(x)必须返回是“true” ;
类推性: 如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true” ;
一致性: 如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true” ;
对称性: 如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
-
任何情况下,x.equals(null)【应使用关系比较符 ==】,永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”
2.3 hashcode:
这是一个native方法,从源码中可以发现:
public int hashCode() {
int lockWord = shadow$_monitor_;
final int lockWordStateMask = 0xC0000000; // Top 2 bits.
final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash).
final int lockWordHashMask = 0x0FFFFFFF; // Low 28 bits.
if ((lockWord & lockWordStateMask) == lockWordStateHash) {
return lockWord & lockWordHashMask;
}
return System.identityHashCode(this);
}
public static native int identityHashCode(Object x);
概念 : Hash 就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出(int),该输出就是散列值。这种转换是一种 压缩映射,也就是说,散列值的空间通常远小于输入的空间。不同的输入可能会散列成相同的输出,从而不可能从散列值来唯一的确定输入值。简单的说,就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
要想进一步了解 hashCode 的作用,我们必须先要了解Java中的容器,因为 HashCode 只是在需要用到哈希算法的数据结构中才有用,比如 HashSet, HashMap 和 Hashtable
实际应用的hash表的添加原则:
- 先调用这个元素的 hashCode 方法,然后根据所得到的值计算出元素应该在数组的位置。如果这个位置上没有元素,那么直接将它存储在这个位置上;
- 如果这个位置上已经有元素了,那么调用它的equals方法与新元素进行比较:相同的话就不存了,否则,将其存在这个位置对应的链表中(Java 中 HashSet, HashMap 和 Hashtable的实现总将元素放到链表的表头)。
也即,定义一个数组,数组内元素为链表,相同的hash值元素存放在同一个链表中,这样,插入和查询都会相对很快。
2.3.1、equals 与 hashCode
前提: 谈到hashCode就不得不说equals方法,二者均是Object类里的方法。由于Object类是所有类的基类,所以一切类里都可以重写这两个方法。
原则 1 : 如果 x.equals(y) 返回 “true”,那么 x 和 y 的 hashCode() 必须相等 ;
原则 2 : 如果 x.equals(y) 返回 “false”,那么 x 和 y 的 hashCode() 有可能相等,也有可能不等 ;
原则 3 : 如果 x 和 y 的 hashCode() 不相等,那么 x.equals(y) 一定返回 “false” ;
原则 4 : 一般来讲,equals 这个方法是给用户调用的,而 hashcode 方法一般用户不会去调用 ;
-
原则 5 : 当一个对象类型作为集合对象的元素时,那么这个对象应该拥有自己的equals()和hashCode()设计,而且要遵守前面所说的几个原则。
相信如何对hash表真正理解了,上述的原则应该很容易理解。
3、小结
- hashcode是系统用来快速检索对象而使用
- equals方法本意是用来判断引用的对象是否一致
- 重写equals方法和hashcode方法时,equals方法中用到的成员变量也必定会在hashcode方法中用到,只不过前者作为比较项,后者作为生成摘要的信息项,本质上所用到的数据是一样的,从而保证二者的一致性
本文主要参考自Java 中的 ==, equals 与 hashCode 的区别与联系
</article>
转子https://blog.csdn.net/Fine1938768839/article/details/79511621