集合
理解底层机制、看源代码,集合的应用
可以动态保存任意多个对象,使用方便 一系列操作对象的方法:增删改查,add、remove、set、get
集合框架体系
单列集合
- List
- Vector
- ArrayList
- LinkedList
- Set
- TreeSet
- HashSet
Map双列集合,存放K-V
- HashMap
- LinkedHashmap
- Hashtable
- Properties
- TreeMap
Collection
接口实现类的特点: 可以存放多个元素,每个元素可以是Object 有些实现类可以存放重复的元素,有些不可以 有些实现类是有序的,有些是无序的 Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的。
- 常用方法,以ArrayList为例
1 | // 创建 |
遍历元素方式
- 使用迭代器
Iterator是一个迭代器,主要用于遍历集合中的元素。仅用于遍历集合,本身不存放对象。
tips:显示所有快捷键,CTRL+J: itit:while迭代 I:for迭代
1 | // 得到一个集合的迭代器 |
- 增强for循环
可以用在集合和数组上使用,底层仍是迭代器
1 | for(Object o : col) |
List
集合类中元素有序,有对应的索引,且可重复。 常用类:Vector、ArrayList、LinkedList 常用方法:
1 | List list = new ArrayList(); |
三种遍历方式: 使用iterator、使用增强for、使用普通for(视作数组)
- ArrayList
注意事项: 可以加入空元素,是由数组实现数据存储的。 基本等同于Vector,但ArrayList执行效率高、线程不安全
源码分析: 底层维护Object数组elementData。 创建对象时如果使用无参构造器,则初始容量为0;第一次添加时,扩容为10;再次扩容为1.5倍 如果使用指定大小的构造器,则初始容量确定;再次扩容为1.5倍
- Vector
底层也是一个对象数组。 线程安全,支持线程同步和互斥。
扩容机制源码分析: 创建对象时如果使用无参构造器,则初始容量为10;再次扩容为2倍 如果使用指定大小的构造器,则初始容量确定;再次扩容为2倍
- LinkedList
底层实现了双向链表和双端队列,可以添加任何元素(可重复、可空),线程不安全、没有同步机制 LinkedList维护了first、last,分别指向首节点和尾节点。 每个节点维护prev、next、item单个属性,通过prev指向前一个,next指向后一个节点。
- list的选择: 查改较多,选择ArrayList 增删较多,选择LinkedList
Set
基于HashMap实现,集合类中元素无序、没有索引,不允许重复的元素,最多包含一个null。 常用类:HashSet、TreeSet 常用方法:和Collection接口相同。 遍历方式:迭代器、增强for
1 | // 创建 |
- HashSet
实现了Set接口,底层实际上是HashMap(数组+链表+红黑树),存储效率高。
元素添加的逻辑: 1.先得到元素的hash值,转换成索引值 2.在存储表的索引位置,看这个位置是否有已经存放的元素 3.如果没有,元素直接加入存储表;如果有,则进行hash值和equals比较,不相同则添加到最后;都相同则不添加。 4.当链表元素超过8,table元素超过64时,则自动进行树化;否则仍采用数组扩容机制
源码解读: 1.首先生成HashMap(); 2.执行add() 3.执行put,方法会执行hash(key)得到key对应的hash值 4.
扩容机制: 1.第一次添加时,数组扩容到16,到达临界值16*0.75时,扩容为16x2;以此类推 2.达到树化条件的时候进行树化。
- LinkedHashSet
是HashSet的子类,底层是LinkedHashMap,维护一个数组+双向链表 根据元素的hashCode值来决定元素的存储位置,同时用链表维护元素的次序,保证存取的有序。
元素添加的逻辑: 1. 添加元素:先求hash值,再求索引确定元素在table中的位置,然后将添加的元素加入到双向链表 2. 可以保证插入的顺序和遍历顺序一致。
- TreeSet
默认是无序的;可以通过调用有参构造器,传入比较器(匿名内部类)来指定排序规则。
Map
双列元素,用于保存具有映射关系的数据key-value key和value是任何引用类型的数据,会封装到HashMap$Node对象中 key不可以重复,value可以重复;出现相同的key会发生替换 常用String类作为key,key-value之间存在单向一对一关系,通过指定的key找到对应的value
1 | // 创建 |
HashMap
- 常用方法
1 | // 创建 |
- 遍历方式
- containsKey:查找键是否存在
- keySet:获取所有的键
- entrySet:获取所有关系的k-v
- values:获取所有的值
1 | // 1.先取出所有的key,通过key取出对应的value |
不保证映射的顺序,底层是以hash表的方式存储。没有实现同步,线程不安全。
元素添加的逻辑: 1.先得到key元素的hash值,转换成索引值 2.在存储表的索引位置,看这个位置是否有已经存放的元素 3.如果没有,元素直接加入存储表;如果有,则对key值进行hash值和equals比较,不相同则添加到最后;都相同则替换value值。 4.当链表元素超过8,table元素超过64时,则自动进行树化;否则仍采用数组扩容机制
扩容机制:和HashSet完全一致 1.第一次添加时,数组扩容到16,到达临界值16*0.75时,扩容为16x2;以此类推 2.达到树化条件的时候进行树化。
HashTable
存放K-V键值对,键和值都不能为空。 使用方法基本和HashMap一样,但sync线程安全、效率低。 根据扩容机制进行扩容:初始大小为11,临界值为8,按照2n+1进行扩容。
Properties
继承自HashTable,并且实现了Map接口,也是使用键值对存放数据。 使用特点和HashTable类似。 可以用于从.properties文件中加载数据到Properties类对象。
TreeMap
默认是无序的;可以通过调用有参构造器,传入比较器(匿名内部类)来指定K的排序规则。
如何选择集合实现类
主要取决于业务操作特点,然后根据集合实现类特性进行选择。
- 先判断存储类型(单列 or 键值对)
- 一组对象:Collection接口 允许重复:List 增删多:LinkedList、改查多:ArrayList 不允许重复:Set 无序:HashSet、排序:TreeSet、插入和取出顺序一致:LinkedHashSet
- 一组键值对:Map 键无序:HashMap、键排序:TreeMap、插入和取出顺序一致:LinkedHashMap 读取文件:Properties
Collections工具类
是一个操作Set、List和Map等集合的工具类,可以对集合元素进行排序、查询和修改。
1 | //创建ArrayList 集合,用于测试. |