[英]Do I need a equals and Hashcode method if my class implements comparable in Java?
我發現這個注釋可以將StringBuffer對象作為Java中TreeSet中的鍵嗎?
“在Java中使用地圖有兩種識別策略(或多或少)。
散列:輸入“Foo”被轉換為盡可能最好的嘗試,以生成唯一訪問數組索引的數字。 (純粹主義者,請不要虐待我,我故意簡化)。 此索引是存儲值的位置。 “Foo”和“Bar”實際上可能生成相同的索引值,這意味着它們都將映射到相同的數組位置。 顯然這不起作用,所以這就是“equals()”方法的用武之地; 它用於消除歧義
比較:通過使用比較方法,您不需要這個額外的消歧步驟,因為比較首先不會產生這種碰撞。 “Foo”等於的唯一關鍵是“Foo”。 一個非常好的想法是,如果你可以將“equals()”定義為compareTo()== 0; 為了一致的緣故。 不是要求。“
我的問題如下:如果我的類實現了可比性,那么它是否意味着我不必重寫equals和hashcode方法來將我的對象用作Hash集合中的鍵。 例如
class Person implements Comparable<Person> {
int id;
String name;
public Person(int id, String name) {
this.id=id;
this.name=name;
}
public int compareTo(Person other) {
return this.id-other.id;
}
}
現在,我可以在Hashable集合中使用我的Person對象嗎?
你通過的文章是在TreeSet
上討論的。 樹集是一棵樹,每個節點都有一個由它的值定義的位置,與樹中已有的其他值相比較。
hashTable
將鍵/值對存儲在哈希表中。 使用Hashtable時,您可以指定用作鍵的對象,以及要鏈接到該鍵的值。 然后對密鑰進行散列,並將得到的散列代碼用作值存儲在表中的索引。
Hashable
和TreeSet
之間的區別在於Hashable
集不需要hashCode
,它只需要知道你是否需要在樹中左右移動項目。 為此你可以使用比較而已。
在hashTable中,比較就足夠了,因為它的構建方式不同,每個對象都通過對其進行散列來到達他的單元格,而不是通過將其與集合中已有的項目進行比較。
所以答案是否定的,你可以'使用compareTo
Person
in hashtable。 你必須覆蓋hashCode()
和equals()
我還建議你閱讀關於哈希表的這篇文章
HashTable確實使用equals和hashCode。 每個班級都有這些方法。 如果您不實現它們,則繼承它們。
是否需要實現它們取決於繼承的版本是否適合您的目的。 特別是,由於Person沒有指定的超類,因此它繼承了Object方法。 這意味着Person對象僅與其自身相等。
您是否需要將兩個不同的Person對象視為與HashTable鍵相等?
如果我的類實現了可比性,那么它是否意味着我不必重寫equals和hashcode方法來將我的對象用作Hash集合中的鍵。 例如
不,您仍然需要實現equals()
和hashCode()
。 這些方法執行非常不同的功能,不能被compareTo()
替換。
equals()
根據對象的相等性返回一個布爾值。 這通常是身份平等而不是字段平等。 這可能與用於比較compareTo(...)
的對象的字段非常不同,盡管如果它對實體有意義,則equals()
方法可以是:
@Overrides public boolean equals(Object obj) { if (obj == null || obj.getClass() != getClass()) { return false; } else { return compareTo((Person)obj) == 0; } }
hashCode()
返回實例的一個整數值,該值在哈希表中用於計算它應該放入的存儲桶。沒有相同的方法可以從compareTo(...)
獲取該值。
TreeSet需要Comparable,以便在樹的右側或左側添加值。 HashMap需要可從Object Class獲得的equals()和Hashcode()方法,但您必須為了您的目的而重寫它們。
如果一個類實現了Comparable
,那么表明該類的實例代表某種類型的值; 通常,當類封裝值時,可能存在兩個不同的實例,它們保持相同的值,因此應該被認為是等價的。 因為不同對象實例被認為是等價的唯一方法是它們覆蓋equals
和hashCode
,這意味着實現Comparable
東西應該覆蓋equals
和hashCode
除非 compare
操作的封裝值將是全局唯一的(暗示不同)實例永遠不應被認為是等價的)。
舉個簡單的例子,假設一個類包含一個long
類型的CreationRank
字段; 每次創建實例時,該成員都設置為從單個AtomicLong
獲取的值, Comparable
使用該字段按創建順序對對象進行排序。 沒有兩個不同的類實例會報告相同的CreationRank
; 因此, x.equals(y)
應該為真的唯一方法是x
和y
引用相同的對象實例 - 完全是默認equals
和hashCode
工作的方式。
順便說一句,讓x.compare(y)
返回零通常意味着x.equals(y)
將返回true,反之亦然,但在某些情況下x.equals(y)
可能為false但x.compare(y)
仍應返回零。 當一個對象封裝一些可以排序的屬性而另一些不能排序時,可能就是這種情況。 例如,考慮一種低級FutureAction
類型,它封裝了DateTime
和DoSomething
接口的實現。 這些事情可以根據封裝的日期和時間進行排名,但可能沒有明智的方法來排列具有相同日期和時間但行動不同的兩個項目。 將equals
報告為false而compare
報告為零比假裝明顯不相等的項目應該被稱為“相等”更有意義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.