一、Set 集合
1.1 LinkedHashSet
- LinkedHashSet 是HashSet的子类
- 底层:数组 + 双向链表
- LinkedHashSet 不允许添加重复元素
- LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
- 源码分析:
- 用 after 和 before 表示前一个结点和后一个结点,所以是双向链表
- 和HashSet底层差不多,只是添加了双向链表维持序列
1.2 TreeSet
- 自动排序
- 里面只能存放同一类型的值
二、Map 集合
2.1 HashMap
- key 不允许重复
- value 可以重复(替换机制)
- 无序
- 将keySet放入Set中,Vlues放入Collection中,Set和Collection指向HashMap$Node
2.2 Map 接口遍历方法
- containsKey:查找键是否存在
- keySet :获取所有键
- entrySet:获取所有关系
- values:获取所有值
案例:Map 遍历的所有方式
public static void main(String[] args) {
Map map = new HashMap();
map.put("no1", "lyq");
map.put("no2", "zs");
// 第一组:先取出所有的 key,通过 key 取 value
// Set set = map.keySet();
// (1) 增强 for
// for (Object o : set) {
// System.out.println(o + "-" + map.get(o));
// }
// (2) 迭代器
// Iterator iterator = set.iterator();
// while (iterator.hasNext()) {
// Object next = iterator.next();
// System.out.println(next + " - " + map.get(next));
// }
// 第二组:取出所有的 values
Collection values = map.values();
// 这里可以使用所有的 Collection 使用的遍历方法
// (1) 增强 for
// 取出所有 value
// for (Object o : values) {
// System.out.println(o);
// }
// (2) 迭代器
// Iterator iterator = values.iterator();
// while (iterator.hasNext()) {
// Object next = iterator.next();
// System.out.println(next);
// }
// 第三组:通过 EntrySet 来获取 k-v
// (1) 增强 for
Set entrySet = map.entrySet(); // EntrySet<Map.Entry<K,V>>
for (Object entry : entrySet) {
// 向下转型 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + " - " + m.getValue());
}
// (2) 迭代器
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry next = (Map.Entry) iterator.next();
System.out.println(next.getKey() + " - " + next.getValue());
}
}
2.3 HashMap 小结
- Map接口常用实现类:HashMap、HashTable
- key 不能重复,底层使用 Set 存放,value 可以重复,底层使用 Collection 存放
- 如果添加相同 key, 相当于修改了原来的值
- 和 HashSet 一样,不保证顺序,因为底层是 hash 表的方式存储
- HashMap 线程不安全,方法没有 synchronized 修饰
- jdk8,HashMap 底层为:数组 + 链表 + 红黑树, jdk7没有红黑树
- 底层剖析:
- HashMap底层维护了
Node类型的数组table,默认为null - 当创建对象时,将加载因子(loadfactor)
初始化为0.75. - 当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key相是否等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。
- 第1次添加,则需要扩容table容量为16,
临界值(threshold)为12 (16*0.75) - 以后再扩容,则需要扩容table容量为原来的2倍(32),临界值为原来的2倍,即24,依次类推
- 在Java8中,如果
一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN TREEIFY CAPACITY(默认64).就会进行树化(红黑树)
- HashMap底层维护了
2.4 HashTable
2.4.1 HashTable 特点介绍
- HashTable 线程安全
- 使用方法和 HashMap 一样
- key 和 value 都不能为空
2.4.2 HashTable 底层分析
- 底层有数组 HashTable$Entry[],初始化大小为 11
- 临界值 threshold 8 = 11 * 0.75
- 按照
int newCapacity = (oldCapacity << 1) + 1的大小扩容,例如 11 扩容 = 23
2.5 TreeMap
- 键排序,值不排序
三、Collections 工具类
- reverse(List) :反转顺序
- shuffle(List):随机排序
- sort(List):升序排序
- swap(List, i, j):将list集合中的 i 和 j 交换
- Object max(Collection) :返回最大值
- Object min(Collection):返回最小值
- int frequency(Collection, Object):返回集合中指定元素出现的次数
- void copy(List dest, List src):复制dest 到 src 中
- boolean replaceAll(List list, Object oldVal, Object newVal):将 list 中所有的 oldVal 替换成 newVal