爲什麼,對於add()
方法TreeSet
和HashSet
狀態在Oracle Java API文檔:約定
如果在所述一組沒有E2元素e只添加其中
(e==null ? e2==null : e.equals(e2))
然而,TreeSet
使用compareTo()
,而HashSet
使用hashCode()
確定平等。兩者都忽略equals()
的值。我擔心文檔不準確,或者是我對約定或算法有錯誤的理解?
爲什麼,對於add()
方法TreeSet
和HashSet
狀態在Oracle Java API文檔:約定
如果在所述一組沒有E2元素e只添加其中
(e==null ? e2==null : e.equals(e2))
然而,TreeSet
使用compareTo()
,而HashSet
使用hashCode()
確定平等。兩者都忽略equals()
的值。我擔心文檔不準確,或者是我對約定或算法有錯誤的理解?
你是正確的TreeSet文檔不正確。
對於HashSet你是錯誤的,因爲它確實使用equals()
。 hashCode()
是而不是用於平等測試,僅用於快速搜索。
TreeSet
解釋了這個在其DOC:
注意,由一組(無論是否提供了明確的比較器)保持的順序必須與equals一致,如果要正確實現Set接口。 (請參閱Comparable或Comparator以獲得與equals一致的精確定義。)這是因爲Set接口是根據equals操作定義的,但TreeSet實例使用其compareTo(或compare)方法執行所有元素比較,所以兩個從這個方法看,被這個方法認爲是相等的元素是相等的。即使排序與等號不一致,集合的行爲也是明確定義的;它只是不服從Set接口的總體合同。
對於HashSet
,這是對文檔隱含的期望,Set
中的對象已正確實現;如果hashCode()
未正確實施,則違反規範但不是HashSet
,而是傳遞給它的對象。
「即使集合的排序與等號不一致,集合的行爲也是明確定義的。」然而,行爲不像文檔中定義的那樣,這正是我想知道的。爲什麼文檔不具體(準確)呢?最好是說:e == null? e2 == null:e.compareTo(e2)== 0) – user3038094
如果hashCode()設置爲始終返回相同的代碼,那麼add()的行爲似乎取決於equals()。但是如果我創建了一個對象,其中equals()總是返回'true'並且不重寫hashCode() - 因此它對於不同的對象是不同的 - 然後add()會添加多個對象。所以add()的行爲似乎比文檔中陳述的更復雜。正如路易斯所說,這些情況不在合同範圍之內,但我對實施感興趣(因爲它沒有按照它的意思去做) - 任何人都知道是否有規範的規範? – user3038094
@ user3038094 - 我會推薦閱讀HashMap的工作原理。那麼你就會明白爲什麼不總是調用'equals()'方法。不管從一般意義上講,HashSet _does_都使用equals()來進行相等性測試。 – jtahlborn
謝謝jtahlborn - 我遵循你的建議,看看你的意思。如果hashCode()不同,那麼該算法不會麻煩評估equals(),如果hashCode()是相同的,則它只使用equals()。據推測這是因爲hashCode()被認爲比equals()更快,或者它是否需要評估hashCode()? 因此,最好在文檔中說: e == null? e2 == null:e.hashCode()== e2.hashCode()? e.hashCode()== e2.hashCode():e.equals(e2)== 0 – user3038094