集合框架:
程序开发并不是解决了业务的基本功能就完成了,很多时候程序运行的环境是有限制的。比如内存小,CPU频率低,或者是像手机这样的设备,能源供应有限。在这种环境下,就需要程序能够在有限的环境中提升效率。这就需要使用数据结构和算法。
但是数据结构与算法即便是学过,也未必在工作时能够用好,而且通用性、性能等等也都是问题。加上学习程序开发的受众群体越来越广,让程序员全部自己实现数据结构与算法不是一个好的主意。所以现在很多语言为了能够提升学习效率,降低学习门槛,同时也为了让程序有更好的执行效率和通用性,就自带了各种实现了数据结构与算法的API集合。在Java中,这就是我们现在要学习的「集合框架」
与现在常见到的数据结构类库一样,Java也是将集合类库的接口(interface)与实现(implementation)分离。所以我们的学习方式一般都是先搞明白接口的分类和关系,然后根据不同的接口来学习对应的实现类。
## 使用集合做什么
搬运数据,集合可以存储数据,然后通过API调用很方便就可以传递大量数据
数据处理,集合中可以直接对数据进行操作,比如统计、去重
-
排序,可以将数据按照需求进行各种排序,然后再传递给调用者
集合的分类:

Java的集合从 Collection 接口和 Map 接口入手
Map 接口和 Collection 没有交集,它有自己的方式,只要标准库后缀不是Map 结尾的,都是直接或者间接实现了Collection接口。
Collection 接口中常见的操作是数据的添加、删除
- add / addAll
- remove / removeAll / removeIf
借助 Iterator 接口,Collection 还具备了数据的循环。
public interface Collection<E> extends Iterable<E>{
//...
// 对数据循环
Iterator<E> iterator();
}```
通过 Iterable 接口, 标准库中的集合都可以使用 forEach 循环。
具体的实现类
| 集合类型 | 描述 |
|---|---|
| ArrayList | 一种可以动态增长和缩减的索引序列 |
| LinkedList | 一种可以在任何位置进行高效地插人和删除操作的有序序列 |
| ArrayDeque | 一种用循环数组实现的双端队列 |
| HashSet | 一种没有重复元素的无序集合 |
| TreeSet | 一种有序集 |
| EnumSet | 一种包含枚举类型值的集 |
| LinkedHashSet | 一种可以记住元素插人次序的集 |
| PriorityQueue | 一种允许高效删除最小元素的集合 |
| HashMap | 一种存储键/ 值关联的数据结构 |
| TreeMap | 一种键值有序排列的映射表 |
| EnumMap | 一种键值属于枚举类型的映射表 |
| LinkedHashMap | 一种可以记住腱/ 值项添加次序的映射表 |
| WeakHashMap | 一种其值无用武之地后可以被垃圾回收器回收的映射表 |
| IdentityHashMap | 一种用 == 而不是用equals 比较键值的映射表 |
Collection

Map

虽然类很多 ,但是我们在教授中只需要交几个类就可以了,分别是下面:
- ArrayList
- LinkedList
- HashSet
- HashMap
- TreeMap
然后加上工具类2个:
- Collections
- Arrays
List
有序集合,可以精确控制列表中每个元素的插入位置。通过整数索引获取列表中的元素。List允许出现重复的值 , 并可以精确控制列表中每个元素的插入位置,通过整数索引获取列表中的元素。
| 方法名 | 说明 |
|---|---|
| add(E e) | 增加单个数据 |
| addAll(Collection<? extends E> c) | 将一个 Collection 集合的数据添加到现在的集合中 |
| remove(Object o) | 删除指定的元素 |
| contains(Object o) | 判断集合是否包含指定的元素 |
| size() | 得到集合的数据总数 |
| isEmpty() | 判断集合是否有数据 |
| get(int index) | 通过索引获取对应的数据元素 |
| set(int index, E element) | 通过索引和新的元素替换原有内容 |
| clear() | 清空数据 |
| toArray() | 将List转为对象数组 |
ArrayList:
ArrayList 是List 接口的大小可变数组的实现。实现了所有可选列表操作, 并允许包括null 在内的所有元素。除了实现List 接口外, 此类还提供一些方法来操作内部用来存储列表的数组的大小( 此类大致上等同于 vector 类, 但 vector 是同步的) 。
ArrayList 的底层是使用数组实现的,看下面的图:

可以看到,数组中的每一个元素,都存储在内存单元中,并且元素之间紧密排列,既不能打乱元素的存储顺序,也不能跳过某个存储单元进行存储。
ArrayList 底层既然是使用数组实现,那么特点就和数组一致:查询速度快,增删速度慢
每个ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数组的大小, 它总是至少等于列表的大小。随着向Array L ist 中小断添加元素, 其容量也自动增长。并未指定增长策略的细节,因为这不只是添加元素会带来分摊固定时间开销那样简单。我们可以使用默认构造函数创建容量为 10 的列表, 也可以初始化指定容量大小。
ArrayList 指定初始容量大小的构造器方法
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}```
常用的操作
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
// 添加数据
list.add(123);
list.add(346);
// 替换数据
list.set(1, 777);
// 将list中的所有数据放到 list2 中
List<Integer> list2 = new ArrayList<>();
list2.addAll( list );
// 循环list2中所有的数据
for (Integer integer : list2) {
System.out.println( integer );
// 删除循环出的对象
list2.remove(integer);
}
// list 集合是否有数据
if( !list.isEmpty() ) {
System.out.println("list.size = "+ list.size());
// 清空 list
list.clear();
}
// 在清空list后,再看list现在有多少数据
System.out.println("list.size = "+ list.size());
}