HashSet
HashSet说明
-
HashSet实现了Set接口
-
HashSet底层是HashMap
private transient HashMap<E,Object> map;//(HashSet的私有属性) //这是HashSet构造器,另几个重载的构造器也是创建了HashMap实例对象 public HashSet() { map = new HashMap<>(); } //HashSet的add方法 public boolean add(E e) { return map.put(e, PRESENT)==null; }
-
可以存放null值,但是只能有一个null值。
-
HashSet取出是无序的,因为存储是在计算Hash值后,在确定索引位置,而遍历是顺序遍历。
-
不能有重复元素.
-
遍历:使用迭代器或增强for循环(实际上还是调用的迭代器),不能使用普通for循环,因为没用提供get方法。
HashSet存储过程
- 添加一个元素时,先计算其Hash值,转换成索引值,hash值是根据hashCode值位运算得到的。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//右移16位尽量减小碰撞
}
//Object提供的hashCode根据元素的地址值返回一个int型整数
-
找到存储数据表table(链表数组),看这个索引位置是否有元素。
-
如果没有,直接加入。
-
如果有,调用equals方法比较(equals方法一般需要自己编写制定比较规则,若不
写,则提供默认,默认比较的是地址值),如果相同,则放弃添加,不相同则加到末尾。)
-
Java8中,如果一条链表元素到达默认数:8, 并且table大小>=64,则会进行树化(红黑树);
详细请查看源码或韩顺平Java基础P522—P525。
覆盖Equals方法一定先覆盖hashCode
方法
先看JDK1.8文档解释:
举个例子:
class person{
String name;
int age;
}
若覆盖了person类中的Equals方法,让判断两个对象是否相等的条件从比较地址值(系统默认提供的equals方法)转变成比较name和age是否相等,若相等则判定对象相等。而此时若不覆盖hashCode方法,则继续按照系统默认提供的比较,那么根据地址值返回的hashCode值必然不同,那么直接判定为不同而走不到equals方法这一步。