java秘钥分散代码,集合-Java HashSet与HashMap

集合-Java HashSet与HashMap

我了解HashSet是基于HashMap实现的,但是在需要唯一的元素集时使用。 那么,为什么在下一个代码中将相同的对象放入地图并进行设置时,两个集合的大小都等于1? 地图大小不应该为2吗? 因为如果两个集合的大小相等,那么使用这两个集合不会有任何区别。

Set testSet = new HashSet();

Map testMap = new HashMap();

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;

}

}

IgorDiy asked 2019-12-25T07:03:48Z

7个解决方案

129 votes

该地图拥有唯一键。 当您使用映射中存在的键调用HashSet时,该键下的对象将被新对象替换。 因此大小为1。

两者之间的区别应该很明显:

在HashSet中存储键值对

在HashSet中,您仅存储密钥

实际上,HashSet具有HashMap字段,并且每当调用add(obj)时,就会在基础映射map.put(obj, DUMMY)上调用put方法-虚拟对象是private static final Object DUMMY = new Object()。因此,该映射以您的对象作为键并填充了一个值 没有兴趣。

Bozho answered 2019-12-25T07:04:25Z

7 votes

Map中的键只能映射到单个值。 因此,第二次使用相同的密钥将put插入地图时,它将覆盖第一个条目。

ColinD answered 2019-12-25T07:04:46Z

6 votes

对于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());

lobster1234 answered 2019-12-25T07:05:06Z

1 votes

我只是想在这些绝妙的答案中添加最后一个难题的答案。 您想知道这两个集合之间的区别是什么,如果它们在插入后返回相同的大小。 好吧,您在这里看不到真正的区别,因为您要使用相同的键在地图中插入两个值,从而用第二个值更改第一个值。 如果您在地图中插入了相同的值,但使用了不同的键,则将看到真正的区别(以及其他)。 然后,您会看到映射中可以有重复的值,但是不能有重复的键,在集合中也不能有重复的值。 这是这里的主要区别。

Nemanja Paripovic answered 2019-12-25T07:05:28Z

1 votes

答案很简单,因为它是HashSets的本质。HashSet在内部使用HashMap,并将虚拟对象命名为PRESENT作为值,此哈希图的KEY将成为您的对象。

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

当您将simpleObject1添加到哈希集时,它将以simpleObject1作为键将其放入其内部哈希图中。 然后,当您添加(simplObject2)时,您将得到false,因为它已经在内部哈希图中作为键可用。

作为一点额外的信息,HashSet通过使用对象的equals()和hashCode()协定有效地使用了哈希函数来提供O(1)性能。 这就是为什么hashset不允许将“ null”(无法实现的equals()和hashCode())实现为非对象的原因。

huseyin answered 2019-12-25T07:06:02Z

0 votes

我认为主要的区别是HashSet在某种意义上是稳定的,它不会替换重复值(如果在插入第一个唯一键之后发现,则将丢弃所有将来的重复值),并且HashMap将努力用新的重复值替换旧的值。 因此,HashMap中必须有插入新重复项的开销。

David Prun answered 2019-12-25T07:06:23Z

0 votes

public class HashSet

extends AbstractSet

implements Set, Cloneable, Serializable

此类实现Set接口,由哈希表(实际上是HashMap实例)支持。 它不保证集合的迭代顺序。 特别是,它不能保证顺序会随着时间的推移保持恒定。 此类允许使用null元素。

该类为基本操作(添加,删除,包含和大小)提供恒定的时间性能,假设哈希函数将元素正确地分散在存储桶中。 对此集合进行迭代需要的时间与HashSet实例的大小(元素的数量)加上后备HashMap实例的“容量”(存储桶的数量)之和成比例。 因此,如果迭代性能很重要,则不要将初始容量设置得过高(或负载因子过低),这一点非常重要。

请注意,此实现未同步。 如果多个线程同时访问哈希集,并且至少有一个线程修改了哈希集,则必须在外部对其进行同步。 通常,通过在自然封装了该集合的某个对象上进行同步来实现。 如果不存在这样的对象,则应使用Collections.synchronizedSet方法将其“包装”。 最好在创建时完成此操作,以防止意外同步访问集更多细节

Jitendra answered 2019-12-25T07:06:58Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值