Java HashSet vs HashMap

Igo*_*Diy 54 java collections

据我所知,这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());
Run Code Online (Sandbox Code Playgroud)

输出为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;
 }
}
Run Code Online (Sandbox Code Playgroud)

Boz*_*zho 129

地图包含唯一键.使用put映射中存在的键调用时,该键下的对象将替换为新对象.因此大小为1.

两者之间的区别应该是显而易见的:

  • Map你存储键值对
  • Set你只存储钥匙

实际上,a HashSet有一个HashMap字段,无论何时add(obj)被调用,该put方法都在底层映射上调用map.put(obj, DUMMY)- 其中虚拟对象是a private static final Object DUMMY = new Object().因此,地图将填充您的对象作为键,以及一个不感兴趣的值.

  • 接受具有不同哈希码的密钥.但是彼此相等的键不是. (2认同)
  • @Bart Kiers - 相等 - 是的,但允许使用相同的哈希码. (2认同)
  • @Bart你可以这样:`public int hashCode(){return 1; 我不推荐它,但它是合法的,并且hashmap可以工作(尽管它的性能会降低.) (2认同)

Col*_*inD 7

a中的键Map只能映射到单个值.所以第二次put使用相同的键进入地图时,它会覆盖第一个条目.


lob*_*234 6

在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());
Run Code Online (Sandbox Code Playgroud)

  • @glowcoder:我们应该总是假设`equals`和`hashCode`的合理(即符合规范)实现. (3认同)
  • 这不完全正确.如果对象上的`.equals()`方法是`return false;`你可以根据需要多次添加同一个对象.我不推荐它. (2认同)