根据源码:
HashSet类中的add()方法:
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
put()方法:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
原理:如果set中的元素与传入值重复,则不再添加进去。
可以看到,关于重复的定义:
- 如果hash码值不相同,说明是一个新元素,存;
- 如果hash码值相同,则继续判断equles:
- 如果hash码值相同,且equles判断相等,说明元素已经存在,不存;
- 如果hash码值相同,且equles判断不相等,说明元素不存在,存;
所以关键是两个方法:hashCode()和equles()
hash:
hash算法计算出的结果就是hash码值;
hash算法的计算方式:
通过对象中的成员来计算出来的结果;
如果成员变量是基本数据类型的值, 那么用这个值直接参与计算;
如果成员变量是引用数据类型的值,那么获取到这个成员变量的hash码值后,再参数计算
例如新建一个Student对象,如果需要用HashSet集合对其进行管理,那么需要重写hashCode()
和equals()
class Student{
private String name;
public Student(String name){
this.name = name;
}
public String getName(){
return name;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Student){
Student student = (Student) obj;
return this.name.equals(student.getName());
}
return super.equals(obj);
}
}