簡體   English   中英

Java HashSet與HashMap

[英]Java HashSet vs HashMap

我了解HashSet基於HashMap實現,但是在需要唯一的元素集時使用。 那么,為什么在下一個代碼中將相同的對象放入地圖並進行設置時,兩個集合的大小都等於1? 地圖大小不應該為2嗎? 因為如果兩個集合的大小相等,那么使用這兩個集合不會有任何區別。

    Set testSet = new HashSet<SimpleObject>();
    Map testMap = new HashMap<Integer, SimpleObject>(); 

    SimpleObject simpleObject1 = new SimpleObject("Igor", 1);
    SimpleObject simplObject2 = new SimpleObject("Igor", 1);
    testSet.add(simpleObject1);
    testSet.add(simplObject2);


    Integer key = new Integer(10);

    testMap.put(key, simpleObject1);
    testMap.put(key, simplObject2);

    System.out.println(testSet.size());
    System.out.println(testMap.size());

輸出為1和1。

SimpleObject code

public class SimpleObject {

private String dataField1;
private int dataField2;

public SimpleObject(){}

public SimpleObject(String data1, int data2){
    this.dataField1 = data1;
    this.dataField2 = data2;
}

public String getDataField1() {
    return dataField1;
}

public int getDataField2() {
    return dataField2;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
            + ((dataField1 == null) ? 0 : dataField1.hashCode());
    result = prime * result + dataField2;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    SimpleObject other = (SimpleObject) obj;
    if (dataField1 == null) {
        if (other.dataField1 != null)
            return false;
    } else if (!dataField1.equals(other.dataField1))
        return false;
    if (dataField2 != other.dataField2)
        return false;
    return true;
 }
}

該地圖擁有唯一鍵。 當您使用映射中存在的鍵調用put ,該鍵下的對象將被新對象替換。 因此大小為1。

兩者之間的區別應該很明顯:

  • Map您存儲鍵值對
  • Set您僅存儲密鑰

實際上, HashSet具有HashMap字段,每當調用add(obj)時,都會在基礎地圖map.put(obj, DUMMY)上調用put方法-其中,虛擬對象是private static final Object DUMMY = new Object() 因此,在地圖中以您的對象作為鍵填充了該值,而這個值沒有意義。

Map的鍵只能映射到單個值。 所以你第二次put到地圖使用相同的密鑰,它覆蓋的第一項。

對於HashSet,添加相同的對象或多或少是無操作的。 如果是HashMap,則將新的鍵,值對與現有的鍵放在一起將覆蓋現有的值,以為該鍵設置新的值。 下面,我在您的代碼中添加了equals()檢查:

SimpleObject simpleObject1 = new SimpleObject("Igor", 1);
SimpleObject simplObject2 = new SimpleObject("Igor", 1);
//If the below prints true, the 2nd add will not add anything
System.out.println("Are the objects equal? " , (simpleObject1.equals(simpleObject2));
testSet.add(simpleObject1);
testSet.add(simplObject2);


Integer key = new Integer(10);
//This is a no-brainer as you've the exact same key, but lets keep it consistent
//If this returns true, the 2nd put will overwrite the 1st key-value pair.
testMap.put(key, simpleObject1);
testMap.put(key, simplObject2);
System.out.println("Are the keys equal? ", (key.equals(key));
System.out.println(testSet.size());
System.out.println(testMap.size());

我只是想在這些絕妙的答案中添加最后一個難題的答案。 您想知道這兩個集合之間的區別是什么,如果它們在插入后返回相同的大小。 好吧,您實際上看不到其中的區別,因為您要在地圖中使用相同的鍵插入兩個值,從而用第二個值更改第一個值。 如果您在地圖中插入了相同的值 ,但是使用了不同的key ,您將看到真正的區別(以及其他)。 然后,您會看到映射中可以重復的值 ,但是不能重復的鍵 ,而在集合中則不能重復的值 這是這里的主要區別。

答案很簡單,因為它是HashSets的本質。 HashSet在內部使用HashMap,並將偽對象PRESENT作為值,並且此哈希圖的KEY將成為您的對象。

hash(simpleObject1)和hash(simplObject2)將返回相同的int。 所以?

當您將simpleObject1添加到哈希集時,它將以simpleObject1作為鍵將其放入其內部哈希圖中。 然后,當您添加(simplObject2)時,您將得到false,因為它已在內部哈希圖中用作鍵。

作為一點額外的信息,HashSet通過使用對象的equals()和hashCode()協定有效地使用了哈希函數來提供O(1)性能。 這就是為什么hashset不允許“ null”的原因,該null無法實現對非對象的equals()和hashCode()。

我認為主要區別在於,HashSet在某種意義上是穩定的,它不會替換重復值(如果在插入第一個唯一鍵之后發現,則將所有將來的重復值丟棄),並且HashMap將努力用新的重復值替換舊值。 因此,HashMap中必須有插入新重復項的開銷。

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, Serializable
此類實現Set接口,該接口由哈希表(實際上是HashMap實例)支持。 它不保證集合的迭代順序。 特別是,它不能保證順序會隨着時間的推移保持恆定。 此類允許使用null元素。

該類為基本操作(添加,刪除,包含和大小)提供恆定的時間性能,假設哈希函數將元素正確地分散在存儲桶中。 遍歷此集合需要的時間與HashSet實例的大小(元素的數量)加上后備HashMap實例的“容量”(存儲桶的數量)之和成比例。 因此,如果迭代性能很重要,則不要將初始容量設置得過高(或負載因子過低),這一點非常重要。

請注意,此實現未同步。 如果多個線程同時訪問哈希集,並且至少有一個線程修改了哈希集,則必須在外部對其進行同步。 這通常是通過對自然封裝了該集合的某個對象進行同步來實現的。 如果不存在這樣的對象,則應使用Collections.synchronizedSet方法將其“包裝”。 最好在創建時完成此操作,以防止意外同步訪問集。 更多詳細信息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM