SiteBean site1 = new SiteBean("http://www.yjbys.com/", ""); SiteBean site2 = new SiteBean("http://www.yjbys.com/", ""); Set<SiteBean> aaSet = new HashSet<>(); aaSet.add(site1); aaSet.add(site2);
System.out.println(site1 == site2); System.out.println(site1.equals(site2)); System.out.println(site1.hashCode() == site2.hashCode()); SiteBean site3 = new SiteBean("http://www.yjby1s.com/11", ""); SiteBean site4 = new SiteBean("http://www.yjby1s.com/11", ""); aaSet.add(site3); aaSet.add(site4);
SiteBean 重寫了hashCode和equals方法,代碼如下: //比較的是域名 @Override public int hashCode() { return siteUrl.hashCode(); } //比較的是域名 @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SiteBean siteBean = (SiteBean) obj; return Objects.equals(siteUrl, siteBean.siteUrl); }
輸出如下:
false true true
且set中元素的個數是2.
set內部實現實際是map,在處理map的key的時候調用了hashcode方法,HashMap中有代碼如下
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
下面嘗試不重寫hashcode方法,即默認使用Object的hashcode方法(代碼省略):
輸出:
false true false
且set中元素的個數是4
調試證明:把元素往set中添加時,首先會對比hashcode是否相等,如果hashcode不相等就直接往set中加這個元素,如果hashcode相等就對比equals方法,如果equals不相等就往set中加這個元素,所以set的元素重復性是根據hashcode和equals方法來判斷的,
對於為什么覆蓋equals方法就一定要覆蓋hashcode方法的原因也顯示了出來:由於是先調用hashcode方法的,如果不覆蓋hashcode方法,默認會去取內存的物理地址作為生成hashcode的依據,那么兩個不同的對象的hashcode必然不同的,於是直接結束添加了,根本沒法調用到equals方法,就不用說equals內部實現如何了,不管equals是返回true還是false都沒機會調用到了。
由於set內部是用map實現的,所以往map中put元素的時候是一樣的原理。
下面嘗試不重寫hashcode和equals方法(代碼省略):
輸出:
false
false false
且set中元素的個數是4
證明如果不重寫hashcode方法,無論equals是返回true還是返回false都沒有用,因為在調用equals方法之前會先調用hashcode方法,在調用hashcode方法的時候
就已經被認為這些對象全部是不重復的元素,直接往set中添加這些對象,並完成添加,equals方法就沒有機會調用到。
作者:歐初權