首先,我们讲讲一般常用的“==”和“equals()”;
“==”运算符用来比较两个变量的值是否相等。也就是说,该运算符用于比较变量对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能使用“==”运算符。
具体而言,如果两个变量是基本数据类型,可以直接使用“==”运算符来比较其对应的值是否相等。如果一个变量指向的数据是对象(引用类型),那么,此时涉及了两块内存,对象本身占用了一块内存(堆内存),变量也占用一块内存,例如,对于赋值语句:
String s = new String();
String t = new String();
变量s占用一块存储空间,而new String()则存储在另外一块存储空间里,此时,变量s所对应内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等(这两个对象是否指向同一块存储空间),这时候就可以用“==”运算符进行比较。但是,如果要比较这两个对象的内容是否相等,那么用“==”运算符就无法实现了。
equals是Object类提供的方法之一。每一个Java类都集成自Object类,所以每一个对象都具有equals这个方法。Object类中定义的equals(Object)方法的情况下,equals(Object)与“==”运算符一样,比较的是引用。
相比“==”运算符,equals(Object)方法的特殊之处就在于它可以被覆盖,所以可以通过覆盖的方法让它不是比较引用而是比较数据内容,例如String类的equals方法是用于比较两个独立对象的内容是否相同,即堆中的内容是否相同,以下面的代码为例:
String s1 = new String("Hello");
String s2 = new String("Hello");
两条new语句创建了两个对象,然后用s1、s2这两个变量分别指向一个对象,这是两个不同的对象,它们的首地址是不同的,即s1和s2中存储的数值是不相同的,所以,表达式s1==s2将返回false,而这两个对象中的内容是相同的,所以,表达式s1.equals(s2)将返回true。
如果一个类没有自己定义equals()方法,那么它将继承Object类的equals()方法,Object类的equals()方法的实现代码如下:
boolean equals(Object object){
return this==object;
}
通过以上例子可以说明,如果一个类没有自己定义equals()方法,它默认的equals()方法(从Object类继承的)就是使用“==”运算符,也是在比较两个变量指向的对象是否是同一对象,此时使用equals()方法和使用“==”运算符会得到同样的结果。若比较的是两个独立的对象,则总返回false。如果编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么必须覆盖equals()方法,由开发人员自己编写代码来决定在什么情况下即可认为两个对象的内容是相同的。
hashcode()和equals()比较:
hashcode简介:
哈希码产生的依据:哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。也有相同的情况,看程序员如何写哈希码的算法。
hashCode()方法和equal()方法的作用其实一样,在Java里都是用来对比两个对象是否相等一致,那么equal()既然已经能实现对比的功能了,为什么还要hashCode()呢?
因为重写的equal()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高,那么hashCode()既然效率这么高为什么还要equal()呢?
因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值得公式可能存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠,所以我们可以得出:
1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
hashCode()方法是从Object类中继承过来的,它也用来鉴定两个对象是否相等。Object类中的hashCode()方法返回对象在内存中地址转换成的一个int值,所以如果没有重写hashCode()方法,任何对象的hashCode()方法都是不相等的。
虽然equals()方法也是用来判断两个对象是否相等的,但是它与hashCode()方法是有区别的。一般来讲,equals()方法是给用户调用的,如果需要判断两个对象是否相等的,可以重写equals()方法,然后在代码中调用,这样就可以判断它们是否相等了。对于hashCode()方法,用户一般不会去调用它,例如在hashmap中,由于key是不可以重复的,它在判断key是否重复时就判断了hashCode()方法,而且也用到了equals()方法。此处“不可以重复”指的是equals()和hashCode()只要有一个不等就可以了。所以,hashCode()方法相当于是一个对象的编码,就好像文件中的md5,它与equals()方法的不同之处就在于它返回的是int型,比较起来不直观。
一般在覆盖equals()方法的同时也要覆盖hashCode()方法,否则,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)集合类(HashMap、HashSet和Hashtable)结合在一起正常运行。
hashCode()方法的返回值和equals()方法的关系如下:
x.equals(y)返回true,即两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode()方法都必须产生同样的整数结果。如果x.equals(y)返回false,即两个对象根据equals()方法比较是不相等的,那么x和y的hashCode()方法的返回值有可能相等,也有可能不相等。反之,hashCode()方法的返回值不相等,一定能推出equals()方法的返回值也不相等,而hashCode()方法的返回值相等,equals()方法的返回值则可能相等,也可能不相等。
hashcode()和equals()关系总结
- 第一种 不会创建“类对应的散列表”
这里所说的“不会创建类对应的散列表”是说:我们不会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中,用到该类。例如,不会创建该类的HashSet集合。
在这种情况下,该类的“hashCode() 和 equals() ”没有半毛钱关系的!
这种情况下,equals() 用来比较该类的两个对象是否相等。而hashCode() 则根本没有任何作用,所以,不用理会hashCode()。 - 第二种 会创建“类对应的散列表”
这里所说的“会创建类对应的散列表”是说:我们会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中,用到该类。例如,会创建该类的HashSet集合。
在这种情况下,该类的“hashCode() 和 equals() ”是有关系的:
1)、如果两个对象相等,那么它们的hashCode()值一定相同。
这里的相等是指,通过equals()比较两个对象时返回true。
2)、如果两个对象hashCode()相等,它们并不一定相等。
因为在散列表中,hashCode()相等,即两个键值对的哈希值相等。然而哈希值相等,并不一定能得出键值对相等。补充说一句:“两个不同的键值对,哈希值相等”,这就是哈希冲突。
此外,在这种情况下。若要判断两个对象是否相等,除了要覆盖equals()之外,也要覆盖hashCode()函数。否则,equals()无效。
例如,创建Person类的HashSet集合,必须同时覆盖Person类的equals() 和 hashCode()方法。
如果单单只是覆盖equals()方法。我们会发现,equals()方法没有达到我们想要的效果。
THAT IS OVER!