HashSet的底层是用HashMap来维护的,所以两个问题可以理解为一个问题。
先看HashSet的部分源码
HashSet 类中的add()方法:
//维护数据的HashMap
private transient HashMap<E,Object> map;
//value的trick值。
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
从源码可以看到,就是把HashSet传入的对象当做HashMap的key进行处理。
put()方法:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
//获取key的hash值
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
//遍历table中的元素
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//关键代码
// 如果hash相同并且 (两个key的对象相同 或者 两个key的equals()返回true)。
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
//此刻返回已经存储的值,所以不会对新的Entry进行存储
return oldValue;
}
}
//修改次数+1
modCount++;
//对新的Entry进行存储
addEntry(hash, key, value, i);
return null;
}
从源码中可以看出,如果有元素和传入对象的hash值相等,那么,继续进行equles()判断,如果仍然相等,那么就认为传入元素已经存在,不再添加,结束,否则仍然添加;