摘要:簡單的一句話結論就是保證你定義的的對象擁有相同的。方法實現等價關系自反性。即一個對象必須等于其自身。對于任意引用值和返回真時,也一定為真傳遞性。發現一樣,調用方法繼續比較,發現個對象一樣。
簡單的一句話結論就是:保證你定義的“equal”的對象擁有相同的hash code。
1)兩個對象equals()為真,則它們的hashCode() 一定相同
2)兩個對象hashCode()相同,equals()不一定為真這兩個Object方法如果沒有很好的定義,可能會產生使用者不希望看到的效果。
2)實現hashCode(),原則如本答案第一句話所示,并盡量使用對象自有特性作為生成因子以減小沖突的概率。
equals方法實現等價關系
1、自反性。
對應任意引用值x,x.equals(x),一定為真。
即一個對象必須等于其自身。
2、對稱性。
對于任意引用值x和y,x.equals(y)返回真時,y.equals(x)也一定為真
3、傳遞性。
對于任意引用值x、y和z,x.equals(y)返回真,且y.equals(z)返回真,則x.equals(z)一定返回真。
4、一致性。
對于任意引用值x和y,如果用于equals比較對象的信息沒有被修改的話,那么多次調用x.equals(y)要么都是true,要么都是false
5、對于任意的非空引用值x,x.equals(null) 一定返回false
下面的例子違反了對稱性
package equals; import java.util.ArrayList; import java.util.List; public final class CaseInsensitive { private String s; public CaseInsensitive(String s) { if(s == null) { throw new UnsupportedOperationException(); } this.s = s; } @Override public boolean equals(Object o) { if(o instanceof CaseInsensitive) { return s.equalsIgnoreCase(((CaseInsensitive) o).s); } // 如果傳進來的是String對象 if(o instanceof String) { return s.equalsIgnoreCase(((String)o)) ; } return false; } public static void main(String[] args) { CaseInsensitive o = new CaseInsensitive("CSP"); String s = "csp"; System.out.println(o.equals(s));// 返回true System.out.println(s.equals(o));;// 返回 false // 根據對稱性,o 與 s 返回true,那么 s 與 o 也應該返回true,而這里卻返回false,違反了對稱性。原因是String的equals方法,不知道要忽略大小寫 //如果將o加入集合中,則返回false,而我們的原意是想讓他返回true Listlist = new ArrayList (); list.add(o); System.out.println(list.contains(s)); // 返回false } }
下面例子違反傳遞性
package equals; /** * Created by Administrator on 2017/9/23. */ public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } public boolean equals(Object o) { if(!(o instanceof Point)) { return false; } Point p = (Point) o; return p.x == x && p.y == y; } }
package equals; public class ColorPoint extends Point { private String color; public ColorPoint(int x, int y,String color) { super(x, y); this.color = color } public boolean equals(Object o) { if(!(o instanceof ColorPoint)) { return false; } ColorPoint p = (ColorPoint) o; return super.equals(o) && p.color.equals(color); } public static void main(String[] args) { ColorPoint cp = new ColorPoint(1,1,"red"); Point p = new Point(1,1); System.out.println(cp.equals(p)); //false System.out.println(p.equals(cp)); //true // 違反了對稱性。因為ColorPoint 與 Point 比較時,多了個color屬性 } }
我們可以對ColorPoint進行修改,讓其滿足對稱性,在混合比較時,忽略顏色信息
.... public boolean equals(Object o) { if(!(o instanceof Point)) { return false; } //對象是Point類型,不是ColorPoint,進行父類級別的比較 if(!(o instanceof ColorPoint)) { return o.equals(this); } ColorPoint p = (ColorPoint) o; return super.equals(o) && p.color.equals(color); } .... public static void main(String[] args) { ColorPoint cp = new ColorPoint(1,1,"red"); Point p = new Point(1,1); ColorPoint cp1 = new ColorPoint(1,1,"black"); System.out.println(cp.equals(p)); //true System.out.println(p.equals(cp1)); //true System.out.println(cp.equals(cp1)); //false // 違反了傳遞性 }
以上代碼雖然符合對稱性,但是卻違反了傳遞性
想要解決以上問題,只能使用復合來代替繼承
public class ColorPoint {
private String color; private Point p; public ColorPoint(String color,Point p) { this.color = color; this.p = p; } public Point getP() { return p; } @Override public boolean equals(Object o) { if(!(o instanceof ColorPoint)) { return false; } ColorPoint cp = (ColorPoint) o; return cp.p.equals(p) && cp.color.equals(color); }
}
當你重寫了equals()時,也應該重寫hashcode();
來看當一個類重寫了equals()方法時,沒有重寫hashCode方法,并將其放入Map中
import java.util.HashMap;
import java.util.Map;
public final class CaseInsensitive {
private int x; private int y; private String s; public CaseInsensitive(int x,int y,String s) { this.s = s; this.x = x; this.y = y; } @Override public boolean equals(Object o) { if(o == this) { return true; } if(!(o instanceof CaseInsensitive) || o == null) { return false; } CaseInsensitive cp = (CaseInsensitive) o; return cp.s.equals(s) && cp.x == x && cp.y == y; } public static void main(String[] args) { CaseInsensitive c = new CaseInsensitive(1,1,"cc"); CaseInsensitive c1 = new CaseInsensitive(1,1,"cc"); Mapm = new HashMap (); m.put(c,"c"); System.out.println(m.get(new CaseInsensitive(1,1,"cc"))); // null }
}
按照我們的意思,應該是返回 c 的,但是實際上返回的是 null
原因在于,沒有重寫hashCode()方法,Map在放入元素時,是先根據對象的散列值進行存放,如果散列值一樣,那么則繼續比較equals方法。此處默認是Object的hashCode方法。所有2個對象不一樣。
讓我們重寫hashCode方法試下
....
@Override
public boolean equals(Object o) { if(o == this) { return true; } if(!(o instanceof CaseInsensitive) || o == null) { return false; } CaseInsensitive cp = (CaseInsensitive) o; return cp.s.equals(s) && cp.x == x && cp.y == y; } //此處使用IDEA 默認生成的hashCode @Override public int hashCode() { int result = x; result = 31 * result + y; result = 31 * result + (s != null ? s.hashCode() : 0); return result; } public static void main(String[] args) { CaseInsensitive c = new CaseInsensitive(1,1,"cc"); CaseInsensitive c1 = new CaseInsensitive(1,1,"cc"); Mapm = new HashMap (); m.put(c,"c"); System.out.println(m.get(new CaseInsensitive(1,1,"cc"))); //返回c }
此時就可以獲取到c了。因為我們重寫了hashCode()方法,比較2個對象的hashCode。發現hashCode一樣,調用equals()方法繼續比較,發現2個對象一樣。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70517.html
摘要:類方法分析聲明文章均為本人技術筆記,轉載請注明出處類簡介類是所有類的父類,在中只有基本數據類型不是對象。對于所有數組類型對象類型基本數據類型數組都繼承于類方法類中通過判斷兩個對象是否具有相同引用,從而判斷兩個對象是否相同子類只要重寫方法,就 Java Object類方法分析 聲明 文章均為本人技術筆記,轉載請注明出處https://segmentfault.com/u/yzwall ...
摘要:如果根據方法得到兩個對象不相同,那么兩個對象的方法的結果不一定不相同,我們可以利用這一點來提高散列表的性能。最后回到文章開頭的問題,如何判斷兩個對象或值是否相同這個問題其實有兩方面的含義,一方面是判斷的方法,另一方面是判斷的效率。 Java中有很多場景需要判斷兩個對象或者兩個值,那么 判斷是否相同的依據是什么? 如何判斷是否相同呢? 為了解釋這個問題,我們從Java語言的根說起,那...
摘要:所以在對象沒有重寫這個方法時,默認使用此方法,即比較對象的內存地址值。結果為可以發現不管對象的內存地址是否相同并不影響其結果,所以類型比較的是數據值而不是內存地址值。 showImg(https://segmentfault.com/img/bVbqpku?w=800&h=344); 今天朋友突然問到一個問題: 兩個對象使用x.equals(y)判斷結果為true時,兩個對象的hash...
摘要:在中對象是一切對象都會自動繼承的一個類,在這個類中定義的屬性和方法可以說是每個類都必須的。這里有必要說說這里對象里面的幾個方法返回該對象的哈希碼值。這些基于表的集合,只能要求被存放的對象實現自己的方法,保證的均勻性。 Object 在Java中Object對象是一切對象都會自動繼承的一個類,在這個類中定義的屬性和方法可以說是每個類都必須的。 這里有必要說說這里對象里面的幾個方法 has...
摘要:相關的文章網上很多了寫這個主要是按自己的思路進行記錄是什么中的實現是一個本地方法生成一個表征當前對象實例的特征值具體的實現根據的實現可能會不同中實際計算的函數的實現如下為時是直接使用的內存地址但默認使用的是的隨 hashcode相關的文章網上很多了, 寫這個主要是按自己的思路進行記錄 hashCode是什么 Object中的hashCode實現是一個本地方法, 生成一個表征當前對象實例...
閱讀 1892·2021-11-23 09:51
閱讀 1535·2021-11-19 09:40
閱讀 3208·2021-11-11 11:01
閱讀 1105·2021-09-27 13:34
閱讀 1835·2021-09-22 15:56
閱讀 2122·2019-08-30 15:52
閱讀 1061·2019-08-30 14:13
閱讀 3473·2019-08-30 14:10