本文详细讲解了集合及其常用的API,还有其底层实现原理。保证让你看完彻底明白Java中的集合以及使用。
在java中集合有两大类:Collection和Map,先来看collection。
Collection
collection是单列集合的祖宗接口,他的功能是全部单列集合都可以继承使用的

Collection中常用的方法
java
public boolean add(E e);//把给定对象添加到当前集合中
public void clear();//清空集合中所有元素
public boolean remove(E e);//删除
public boolean contains(Object obj);//判断当前集合是否包含obj
public boolean isEmpty();//判断集合是否为空
public int size();//返回集合元素的个数(长度)
Collection是一个接口,不能直接创建它的对象,只能利用多态创建。如下:
java
public class CollectionDemo1 {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
System.out.println(coll);
//删除不能通过索引删除 只能通过元素对象删除
coll.remove("aaa");
System.out.println(coll);
//判断元素是否包含
//contains底层依赖equals判断
//注意:如果是自定义对象 必须要重写equals方法,因为equals比较的是地址值,不是变量值
boolean re = coll.contains("bbb");
System.out.println(re);
//判断集合是否为空
boolean r1 = coll.isEmpty();
System.out.println(r1);
//获取集合长度
int l = coll.size();
System.out.println(l);
}
}
Collection的遍历
在java中很少使用普通for循环进行遍历,因为Set集合是没有索引的。下面介绍几种常用的遍历。
其中如果在遍历的过程中需要删除元素,请使用迭代器;如果仅仅是遍历,使用增强for或者Lambda表达式。
迭代器遍历
java
Iterator<String> it = list.iterator();//获取迭代器
while(it.hasNext()){//判断当前位置是否有元素
String str = it.next();//获取当前位置元素,并将迭代器移动到下一位置
System.out.println(str);
}
增强for遍历
- 增强for的底层就是迭代器,为了简化迭代器的代码书写的。
- 它是JDK5之后出现的,其内部原理就是一个Iterator迭代器。
- 所有的单列集合和数组才能用增强for进行遍历。
使用格式如下:
java
for(String s:List){
System.out.println(s);
}
java
public class demo {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
//s就是第三方变量,在循环中依次表示集合中的一个数据
//快捷方式 集合名字+ for +回车
for(String s: coll){
System.out.println(s);
}
}
}
细节注意⚠️
- 修改增强for中的变量,不会改变集合中原本的数据。
Lambda表达式遍历
它是在JDK8开始的新技术,提供一种更简单、更直接的遍历集合的方式。
java
public class demo {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
//利用匿名内部类表示
coll.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//利用Lambda表达式表示
coll.forEach(s -> System.out.println(s));
}
}
List集合
List集合的特点:
- 有序:存和取的元素顺序一致。
- 有索引:可以通过索引操作元素。
- 可重复:存储的元素可以重复。
- List继承了Collection的方法
- 因为List有索引,所以增强了所以操作方法
List集合特有索引的方法

java
public class demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
System.out.println(list);
// 在指定位置添加数据
list.add(1,"ddd");
System.out.println( list);
// 删除指定位置的数据
list.remove(1);
list.remove("ddd");
System.out.println(list);
// 修改指定位置的数据
list.set(1,"eee");
System.out.println(list);
// 获取指定位置的数据
System.out.println(list.get(1));
}
}
List集合的遍历方式
迭代器遍历
java
public class demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
System.out.println(next);
}
}
}
列表迭代器遍历
java
public class demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//额外添加一个方法,可以添加元素
ListIterator<String> it = list.listIterator();
while (it.hasNext()) {
String str = it.next();
if("bbb".equals(str)) {
it.add("qqq");
}
}
System.out.println(list);
}
}
增强for遍历
java
public class demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (String s : list) {
System.out.println(s);
}
}
}
Lambad表达式遍历
java
public class demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.forEach(s->System.out.println(s));
}
}
普通for循环
java
public class demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
数据结构
数据结构是计算机底层存储、组织数据的方式。是指数据之间是以什么样的方式排列在一起的。数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。
需要思考三问题:每种数据结构长什么样子?如何添加数据?数据删除数据?
常见的八种数据结构
- 栈 :先进后出、后进先出
- 队列:先进先出、后进后出
- 数组:查询快、数据在内存中连续存储;添加删除效率低,需要移动数据
- 链表:每个节点独立、查询慢、增删相对快
- 二叉树
- 二叉查找树
- 平衡二叉树
- 红黑树
红黑树
红黑树是一种自平衡的二叉查找树。红黑树是一种特殊的二叉查找树,每个节点都有存储位表示节点的颜色,每一个节点可以是红或者是黑,红黑树不是高度平衡的,它的平衡是通过红黑规则进行实现的。
红黑树规则
- 每个节点或是红色或是黑色
- 根结点必须是黑色
- 如果一个节点没有父节点或者子节点,那么该节点相应指针的属性值为Nil,这些Nil视为叶节点,每个叶节点是黑色的
- 如果一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点项链的情况)
- 对每一个节点,该节点到其所有后代叶节点的简单路径上,均包含相同数据的黑色节点。
红黑树添加规则

ArrayList集合
ArrayList集合底层原理
ArrayList底层是数组。
- 利用空参创建的集合,在底层创建一个默认长度为0的数组。
- 添加第一个元素时,底层会创建一个新的长度为10的数组,默认都是null。
- 存满时,自动扩容1.5倍。
- 如果一次添加多个元素,1.5倍放不下,则新创建的数组的长度以实际为准。
LinkedList集合
底层的数据结构是双向链表,查询慢,增删快,但是如果是操作首尾元素,速度也是很快的。

LinkedList集合独有的方法

泛型
泛型是JDK5中引入的特性,可以在变异阶段约束操作的数据类型,并进行检查。
泛型的格式:<数据类型> // 泛型只支持引用数据类型。
泛型的好处:
- 统一数据类型;
- 把运行时期的问题提前提前了编译期间,避免了强制类型转换出现的可能,因为在编译阶段类型就能确定下来。
泛型的细节注意: - 泛型中不能写基本数据类型;
- 指定具体类型后,传递数据时可以传入该类类型或者其子类类型;
- 如果不写泛型,默认是Object。
泛型类
当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
修饰符 class 类名<类型>{
}
类型可以用E、T、K、V等替代,可以理解为变量。
泛型方法
方法中形参类型不确定时可以使用类面后面定义的泛型(所有的方法都能用)或者在方法申明上定义自己的泛型(只有本方法可以用)。
修饰符 <类型> 返回值类型 方法名 (类型 变量名){
}
java
public <T> void show(T t){
}
泛型接口
修饰符 interface 接口名 <类型> {
}
java
public interface List<E>{
}
Set集合
- 无序
- 不重复
- 无索引
Set接口中方法基本与Collection的API一致。
HashSet集合
无序,不重复,无索引
HashSet底层采取哈希表存储数据,哈希表JDK8之前是数据+链表,JDK8开始是数据+链表+红黑树。
哈希值:对象的整数表现形式。根据hashCode方法计算出来的int类型的整数。需要重新写hashCode方法,利用对象内部的属性值计算哈希值。如果不重写,不同对象计算出的哈希值不同,如果重新写,不同对象只要属性值相同,计算出的哈希值就是一样的。
哈希表JDK8之前是数据+链表:
- 创建一个默认长度16,默认加载因子0.75的数组,数组名是table;
- 根据元素的哈希值跟数组长度计算应存入的位置。
- 判断是否是null,如果null直接添加
- 如果不是null,比较属性值,
- 一样:不存。 不一样:存入数组,形成链表。(JDK8之前,新元素存入数组,老元素挂在下面。JDK8以后,新元素直接挂在老元素下面,当链表长度超过8,数组长度大于等于64时,自动转为红黑树)
LinkedHashSet
有序,不重复,无索引
底层数据结构依然是哈希表,只是每个元素又额外多了一个双链表的机制记录存储的顺序。
TreeSet
不重复,无索引,可排序
可排序:默认从小到大排序。
Treeset底层基于红黑树的数据结构实现排序的,增删改查性能都比较好。
双列集合Map

Map常用的API

Map的遍历方式
键找值
java
public class demo {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1111");
map.put("2", "2222");
map.put("3", "3333");
//获取所有的键 放入单列集合
Set<String> keys = map.keySet();
for (String key : keys){
System.out.println(key);
//获取值
System.out.println(map.get(key));
}
}
}
键值对
java
public class demo {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1111");
map.put("2", "2222");
map.put("3", "3333");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
Lambda表达式
java
public class demo {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("1", "1111");
map.put("2", "2222");
map.put("3", "3333");
map.forEach( (key,value) -> System.out.println(key + ":" + value));
}
}
HashMap
- HashMap是Map的一个实现类;
- 没有额外的特有方法,直接使用Map里面的方法;
- 特点都是由键觉定的:无序、不重复、无索引;
- HashMap和HashSet的底层原理是一样的,都是哈希表结构。
LinkedHashMap
- 由键决定:有序,不重复,无索引;
底层数据结构依然是哈希表,只是每个元素又额外多了一个双链表的机制记录存储的顺序。
TreeMap
- 跟TreeSet底层原理一样,都是红黑树结构的
- 由键决定:不重复,无索引,可排序(默认从小到大,可以自定义)。
Collections
- 是集合工具类
常用的API:
