集合知识解析(中)
- #先补充一下ArrayList 与vector 的区别,通过一个表格
底层结构 | 版本 | 线程安全 | 自动扩容倍数 | |
---|---|---|---|---|
ArrayList | 可变数组 | jdk1.2 | 不安全,效率高 | 1. 有参构造扩容成原来参数的1,5倍 2. 无参构造,第一次是10,第二次开始为1.5倍扩容 |
Vector | 可变数组Objec[] | jdk1.0 | 安全,效率低 | 1. 如果指定大小,则每次自动扩容按照原来的2倍进行 2. 无参构造,默认为10,数组满了之后按照2倍扩容 |
一、 LinkedList 集合
1. 了解单项链表
-
- 概念:LinkedList 底层实现了双向链表
-
- 可以添加任何元素(元素可以重复),包括null
-
- 线程不安全
-
学习之前,先了解一下单链表的实现原理,如图所示
- 优点:随机增删效率高
- 缺点:检索效率低,因为没有下标,可以在任何位置生成,不容易被检索
2. Linked List底层结构
- LinkedList底层维护了一个双向链表
- LinkedList中维护了两个属性first和last 分别指向首节点和尾结点
- 每个结点(Node对象),里面又维护了prev、nex、item三个属性,其中通过prev指向前一个,通过next指向后一个结点,最终实现双向链表
- 所以LinkedList的的元素添加和删除,不是通过数组来完成的,相对来说效率较高
- ArrayList 和LinkedList 的比较
底层结构 | 增删效率 | 改查效率 | |
---|---|---|---|
ArrayList | 可变数组 | 较低,数组扩容 | 较高 |
LinkedList | 双向链表 | 较高,通过链表追加 | 较低 |
- 如何选择ArrayList 和LinikedList
- 如果我们改查操较多,选择ArrayList
- 如果增删操作较多,选择LinkedList
- 一般来说,在程序中80%-90%是查询,大部分情况选择ArrayList
- 在一个项目中根据业务员灵活选择,可以能一个模块是ArrayList,另一个模块是LinkedList,具体情况具体分析
二、Set接口
- 概念:
- 无序(添加和取出的顺序不一致),没有索引
- 不允许重复元素,所以最多包含一个null
- 主要实现类 TreeSet、HashSet
- 常用方法
和List接口一样,Set接口也是Collection子接口,因此,常用方法和Collection接口一样
- 遍历方式
- 和Collection的遍历方式一样,因为Set接口也是Collection子接口
- 可以使用迭代器
- 增强for循环
- 不能使用索引的方式来获取
Set接口实现类HashSet
- HashSet集合底层是HashMap,所以我们主要研究的是HashMap
// 源码
public HashSet() {
map = new HashMap<>();
}
- 通用方法
方法 | 解释 |
---|---|
put(KEY, VALUE) | 添加键值对 |
get(object key) | 通过键获取键对应的值 |
keySet() | 返回Set###集合 |
values() | 返回Collection |
clear() | 清空map集合 |
remove(Object key) | 根据传入的键删除键值对 |
size() | 返回键值对的个数 |
containsValue(Object value) | 根据传入的value值判断集合中是否包含此value |
containsKey(Object key) | 根绝掺入的key值判断集合中是否包含此key |
isEmpty() | 判断集合是否为空 size() == 0 |
Set<Map.Entry<K,V>>entrySet() | 输出集合对应的键值对 |
map遍历
- 通过实例进行分析
3个方法
- Set<Map.Entry<K,V>>entrySet() 方法 (优选)
- keySet方法 (可选)
- values 方法 (不推荐)
import java.util.*;
public class Test01 {
@SuppressWarnings("all")
public static void main(String[] args) {
// map 循环
// 1.Set<Map.Entry<K,V>>entrySet() 方法
HashMap<Integer,String> hm = new HashMap<Integer,String>();
hm.put(1,"司马懿");
hm.put(2,"鲁肃");
hm.put(3,"周瑜");
hm.put(4,"诸葛亮");
hm.put(5,"张良");
// 强转成Set
// static class Node<K,V> implements Map.Entry<K,V>
// Map.Entry<Integer,String> 这是一个类,多态父类型引用指向子类型对象,Set集合指向Node对象(实现了Map.Entry接口)
System.out.println("===========Set<Map.Entry<K,V>>entrySet()方法==========");
Set<Map.Entry<Integer,String>> ss = hm.entrySet();
Iterator<Map.Entry<Integer,String>> iterator = ss.iterator();
while (iterator.hasNext()) {
Map.Entry<Integer,String> node = iterator.next();
System.out.println(node);
}
// keySet方法
System.out.println("\n\n===========keySet方法==========");
Set <Integer> keySet = hm.keySet();
Iterator<Integer> iterator1 = keySet.iterator();
while (iterator1.hasNext()) {
Integer next = iterator1.next();
System.out.println(next);
}
// values 方法
System.out.println("\n\n===========values 方法==========");
Collection<String> cs = hm.values();
Iterator<String> iterator2 = cs.iterator();
while (iterator2.hasNext()) {
String next = iterator2.next();
System.out.println(next);
}
}
}
- 运行结果
===========Set<Map.Entry<K,V>>entrySet()方法==========
1=司马懿
2=鲁肃
3=周瑜
4=诸葛亮
5=张良
===========keySet方法==========
1
2
3
4
5
===========values 方法==========
司马懿
鲁肃
周瑜
诸葛亮
张良
三、泛型
-
概念:对类型不确定的表达
-
语法:定义泛型 <标识符>
-
场景: 类型<> 方法<>
类型 | 方法 |
---|---|
T | element |
E | type |
K | Key |
V | Value |
- 集合当中泛型
public abstract class AbstractList<E>{}
泛型在集合中:
1. 使用集合的时候没有确定泛型,那么泛型是Object
2. 统一集合的元素类型