Set 接口
- 无序(添加和取出顺序不一致)(但取出顺序固定)。
- 没有索引。
- 不允许重复,所以最多一个
null
。 - 遍历方式
- 迭代器
- 增强for循环
- 不能使用普通for循环索引方式。
HashSet
- 实现了Set接口,具有相应特征。
- 底层实际是HashMap,HashMap底层是数组+链表/红黑树。
- add()方法会返回一个boolean值,表示添加成功/失败。
Set set = new HashSet(); set.add("Lucy"); set.add("Lucy");//False set.add(new Dog ("tom")); set.add(new Dog ("tom"));//True。 //由于 Dog 类没有重写 equals 和 hashCode 方法, //这两个 Dog 对象会被认为是不同的对象,因此这个 Dog 对象也会被添加到 set 中。 set.add(new String("hsp")); set.add(new String("hsp"));//False //再次添加一个新的 String 对象,虽然它是通过 new String("hsp") 创建的, //但 String 类重写了 equals 和 hashCode 方法,因此这两个 String 对象被认为是相同的,不会被重复添加。
- HashSet 不允许重复元素,判断重复的依据是 equals 和 hashCode 方法。
HashSet 添加元素底层实现
- 先得到元素Hash值,转换成数组索引值。
- 找到table数组的索引位置有无元素。
- 没有则直接加入;有则调用equals方法比较,相同则放弃添加,不同则与下一个链接的元素比较···
HashSet 扩容机制与树化机制
- 首次添加元素,table扩容至16。临界值threshold=加载因子loadFactor(0.75)*16=12。
- 如果元素个数达到临界值12,则table扩容两倍为32。 此时临界值threshold=加载因子loadFactor(0.75)*32=24·····
- 如果一条链表的元素个数达到8,并且table大小达到64,则该链表将进行树化。否则仍采用扩容机制
LinkedHashSet
- 继承了HashSet,实现了Set接口,具有相应特征。
- 添加和取出顺序一致咯。
- 底层实际是LinkedHashMap,LinkedHashMap底层是数组+双向链表。
- 双向链表有head和tail,每一个节点有pre和next。
- 数组是
HashMap$Node[]
,存放的元素是LinkedHashMap$Entry
类型。