集合类一
目录
走进集合类
集合和数组一样,可以表示同样的一组元素,它们的
相同点:
- 它们都是容器,都能够容纳一组元素。
不同点:
- 数组的大小是固定的,集合的大小是可变的。
- 数组可以存放基本数据类型,但集合只能存放对象(只能是引用类型)。
集合框架
什么是集合框架:
Java 集合框架 Java Collection Framework ,又被称为容器 container ,是定义在 java.util 包下的一组接口 interfaces 和其实现类 classes 。
其主要表现为将多个元素 element 置于一个单元中,用于对这些元素进行快速、便捷的存储 store 、检索 retrieve 、 管理 manipulate ,即平时我们俗称的增删查改 CRUD 。
类和接口总览:
容器背后对应的数据结构:
每个容器其实都是对某种特定数据结构的封装
1. Collection:是一个接口,包含了大部分容器常用的一些方法
2. List:是一个接口,规范了ArrayList 和 LinkedList中要实现的方法
- ArrayList:实现了List接口,底层为动态类型顺序表
- LinkedList:实现了List接口,底层为双向链表
3. Stack:底层是栈,栈是一种特殊的顺序表
4. Queue:底层是队列,队列是一种特殊的顺序表
5. Deque:是一个接口
6. Set:集合,是一个接口,里面放置的是K模型
- HashSet:底层为哈希桶,查询的时间复杂度为O(1)
- TreeSet:底层为红黑树,查询的时间复杂度为O(
),关于key有序的
7. Map:映射,里面存储的是K-V模型的键值对
- HashMap:底层为哈希桶,查询时间复杂度为O(1)
- TreeMap:底层为红黑树,查询的时间复杂度为O(
),关于key有序
集合根接口
所有的集合类最终都是实现自集合根接口的。
集合类的继承关系相当复杂,但是最顶层都会实现自Collection类。这个接口定义了集合类的一些基本操作。
List列表
在集合框架中,List是一个接口,继承自Collection。
List是集合类型的一个分支,它的主要特性有:
- 是一个有序的集合,插入元素默认是插入到尾部,按顺序从前往后存放,每个元素都有一个自己的下标位置。
- 列表中允许存在重复元素(equals方法)。
List的常用方法:
方法 | 解释 |
boolean add(E e) | 尾插 e |
void add(int index, E element) | 将 e 插入到 index 位置 |
boolean addAll(Collection c) | 尾插 c 中的元素 |
E remove(int index) | 删除 index 位置元素 |
boolean remove(Object o) | 删除遇到的第一个 o |
E get(int index) | 获取下标 index 位置元素 |
E set(int index, E element) | 将下标 index 位置元素设置为 element |
void clear() | 清空 |
boolean contains(Object o) | 判断 o 是否在线性表中 |
int indexOf(Object o) | 返回第一个 o 所在下标 |
int lastIndexOf(Object o) | 返回最后一个 o 的下标 |
List subList(int fromIndex, int toIndex) | 截取部分 list |
List的使用:
List是个接口,并不能直接用来实例化。
如果要使用,必须去实例化List的实现类。在集合框架中,ArrayList和LinkedList都实现了List接口。
一般的,如果我们要使用一个集合类,我们会使用接口的引用:
public static void main(String[] args) {
List<String> list=new ArrayList<>(); //使用接口的引用来操作具体的集合类实现,是为了方便日后如果
// 我们想要更换不同的集合类实现,而且接口中本身已经定义了主要的方法,故没必要直接实现类
list.add("AAA"); //使用add添加元素
list.clear();
System.out.println(list); //打印集合类,可以得到一个非常规范的结果
}
LinkedList是一个双向链表。
迭代器
元素的遍历:
public static void main(String[] args) {
List<String>list1=new LinkedList<>(Arrays.asList("A","B","C"));
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
//支持使用foreach语法,编译后使用的是List的迭代器在进行遍历操作
for (String s:list1) System.out.println(s);
}
使用迭代器对集合中的元素进行遍历 :
因为集合类的实现方案有很多,可能是链式存储,也可能是数组存储,不同的实现有着不同的遍历方式,而迭代器则可以将多种多样不同的集合类遍历方式进行统一,只需要各个集合类根据自己的情况进行对应的实现就可以了。
public static void main(String[] args) {
List<String>list1=new LinkedList<>(Arrays.asList("A","B","C"));
//通过调用iterator方法快速获取当前集合的迭代器
//Interator迭代器本身也是一个接口,由具体的集合实现类来根据情况实现
Iterator<String>iterator=list1.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
在ArrayList和LinkedList中迭代器的实现不同,ArrayList直接按下标访问,LinkedList就是不断向后寻找结点,但都按照迭代器的标准进行了实现。
注意:迭代器的使用是一次性的,用了之后就不能再用了。如果需要再次进行遍历操作,那么需要重新生成一个迭代器对象,为了简便我们可以直接使用‘foreach’语法来快速遍历集合类,效果是完全一样的
在Java8中提供了一个支持Lambda表达式的forEach方法,这个方法接受一个Consumer,也就是对遍历的每一个元素进行操作,这个效果和上面的写法是完全一样的,因为forEach方法内部本质上也是迭代器在处理,这个方法是在lterable接口中定义的:
public static void main(String[] args) {
List<String>list1=new LinkedList<>(Arrays.asList("A","B","C"));
list1.forEach(str ->System.out.println(str));
//可替换为Lambda表达式
}
得益于Iterable提供的迭代器生成方法,实际上只要是实现了迭代器接口的类(包括我们自己写的),都可以使用foreach方法。
ListIterable:
这个迭代器是针对于List的强化版本,增加了更多方便的操作,因为List是有序集合,所以它支持两种方向的遍历操作,可以从后向前,从前向后。
public static void main(String[] args) {
List<String>list=new ArrayList<>(Arrays.asList("a","b","c"));
ListIterator<String>iterator1=list.listIterator();
iterator1.next();
iterator1.set("n");
System.out.println(list);
}