点击“开发者技术前线”,选择“星标”
让一部分开发者先看到未来
回复“666”,获取一份专属大礼包
==
用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据(注意是基本类型)或两个 引用变量是否相等,只能用==操作符。
假如一个变量指向的数据是对象类型的,例如Objet obj 1= new Object() 那么,这时候涉及了两块内存;变量 obj1 是一个内存,new Object() 是另一个内存(堆内存),此时,变量 obj1 所对应的内存中存储的数值就是对象占用的那块内存(堆内存)的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即要看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较;
hashcode()
hashCode 的存在主要用于查找的快捷性,如 Hashtable, HashMap 等,hashCode 是用来在三列存储结构中确定对象的存储地址的。
如果两个对象相同,就是适用于 euqals(java.lang.Object) 方法,那么这两个对象的 hashCode一定相同。
如果对象的euqals 方法被重写,那么对象的 hashCode 也尽量重写,并且产生 hashCode 使用的对象,一定要和 equals 方法中使用的一致,否则就会违反上面提到的第二点。
两个对象的 hashCode 相同,并不一定表示这两个对象就相同,也就是不一定适用于equals() 方法,只能够说明这两个对象在三列存储结构中,如 Hashtable.,他们存在同一个篮子里。
以上话以前摘录自一篇博客,讲的非常好。
equals(Object obj)
如果一个类没有重写 equals(Object obj)方法,则等价于通过 == 比较两个对象,即比较的是对象在内存中的空间地址是否相等。
如果重写了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;
}
}
结果
即使两个A 对象通过 equals() 比较返回true,但HashSet 依然把他们当成 两个对象,即使两个 B 对象 的hashCode() 返回值相同,但HashSet 依然把他们当成两个对象。
即也就是,当把一个对象放入HashSet 中时,如果需要重写该对象对应类的 equals() 方法,则也应该重写其 hashCode() 方法。规则是:如果两个对象通过 equals() 方法比较返回true,这两个对象的 hashCode 值也应该相同。
如果两个对象通过euqals() 方法比较返回true,但这两个对象的 hashCode() 方法返回不同的hashCode 值时,这将导致HashSet 会把这两个对象保存在 Hash 表的不同位置,从而使两个对象都可以添加成功,这就与 Set 集合的规则冲突了。
如果两个对象的 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
后台回复“面试” “资料” 领取一份干货,数百技术面试手册等你
历史推荐
阿里面试官:ThreadLocal的使用场景?与Synchronized相比有什么特性?
好文点个在看吧!