一、Collection
1.1 概述
- Collection 层次结构 中的根接口。
- Collection 表示一组对象,这些对象也称为 collection 的元素【集合中只能存储引用类型】。
- 一些 collection 允许有重复的元素,而另一些则不允许。
- 一些 collection 是有序的,而另一些则是无序的。
- JDK 不提供此接口的任何 直接实现:它提供更具体的子接口(如 Set 和 List)实现。
- 此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
1.2 Collection体系
- Collection接口:
- 这是所有集合类的根接口,定义了添加、删除、迭代等基本方法。
- 实现
Collection
接口的类有ArrayList
,LinkedList
,HashSet
,TreeSet
,Vector
,Stack
等。
- List接口:
List
是一个有序的集合,允许重复元素,并且每个元素都有一个位置索引。- 实现
List
接口的类有ArrayList
,LinkedList
,Vector
等。
- Set接口:
Set
是一个不包含重复元素的集合,没有顺序的概念。- 实现
Set
接口的类有HashSet
,LinkedHashSet
,TreeSet
等。
- Queue接口:
Queue
是一个主要用于实现队列操作的集合,如先进先出(FIFO)。- 实现
Queue
接口的类有ArrayDeque
,LinkedList
等。
- Deque接口:
Deque
是双端队列的缩写,可以作为堆栈、队列或列表使用。- 实现
Deque
接口的类有ArrayDeque
,LinkedList
等。
- Map接口:
Map
是一种将键映射到值的对象,不允许重复键。- 实现
Map
接口的类有HashMap
,LinkedHashMap
,TreeMap
,Hashtable
,Properties
等。
除了上述接口,还有一些辅助类和接口,例如Iterator
用于遍历集合,Spliterator
用于并行流处理,EnumSet
用于枚举类型集合等。
Java Collection Framework的设计遵循了一些基本原则,如泛型化、可变性、线程安全性等,使得开发人员能够更加高效地处理各种数据结构问题。
1.3 常用方法
增删改查
import java.util.ArrayList;
import java.util.Collection;public class Demo02 {public static void main(String[] args) {/*** 方法摘要 * 增boolean add(E e) 确保此 collection 包含指定的元素(可选操作)。 boolean addAll(Collection<? extends E> c) 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 * 删boolean remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 boolean removeAll(Collection<?> c) 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 void clear() 移除此 collection 中的所有元素(可选操作)。 * 改* 查int size() 返回此 collection 中的元素数。 boolean isEmpty() 如果此 collection 不包含元素,则返回 true。 boolean contains(Object o) 如果此 collection 包含指定的元素,则返回 true。 boolean containsAll(Collection<?> c) 如果此 collection 包含指定 collection 中的所有元素,则返回 true。 boolean retainAll(Collection<?> c) 仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。 *//*** 创建集合对象* 多态方式创建对象:* 声明的容器对象类型是接口,实际创建的对象类型是实现类* 声明了容器对象中的元素类型是String【泛型】*/Collection<String> coll = new ArrayList<String>();// 添加数据coll.add("曹操");coll.add("曹丕");coll.add("曹植");coll.add("曹昂");// 输出容器中的内容System.out.println(coll.toString());Collection<String> c = new ArrayList<String>();// 添加数据c.add("曹爽");c.add("曹冲");c.add("曹洪");// 添加指定集合中的全部数据c.addAll(coll);System.out.println(c);// 删除数据,有布尔类型的返回值,表示删除是否成功coll.remove("曹昂");System.out.println(coll);// 移除两个集合中交集部分c.removeAll(coll);System.out.println(c);System.out.println("集合中元素的数量:" + c.size());// 清空集合// c.clear();System.out.println("集合中元素的数量:" + c.size());// 集合中是否包含指定元素System.out.println(c.contains("曹操"));System.out.println(c.contains("曹爽"));// 是否完全包含另一个集合中的数据System.out.println(c.containsAll(coll));System.out.println(c.containsAll(c));coll.add("曹爽");coll.add("曹冲");System.out.println(c);System.out.println(coll);// 在c集合中留下两个集合中交集部分内容c.retainAll(coll);System.out.println(c);}
}
遍历集合【重点】【掌握】
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;public class Demo03 {public static void main(String[] args) {/*** 遍历* foreach* iterator*/// 创建集合Collection<String> names = new ArrayList<String>();// 添加数据names.add("唐三藏");names.add("孙悟空");names.add("猪八戒");names.add("沙和尚");names.add("白龙马");/*** foreachfor(数据类型 变量名 : 容器对象){}容器对象:数组、集合数据类型:容器中元素的类型变量名字:临时变量名字,用来存储容器中的每一个元素*/for (String name : names) {System.out.println(name);}/*** 迭代器* 先使用获取迭代器对象:* 调用集合的iterator()方法* 使用循环从迭代器中获取每一个元素* 使用while循环*/Iterator<String> it = names.iterator();// 不断地判定是否有下一个数据while (it.hasNext()) {// 获取下一个对象,顺便把游标向下移动String name = it.next();System.out.println(name);}}
}
二、List
2.1 概述
- 有序地Collection
- 元素有索引
- 元素能重复
- 每个元素的插入位置进行精确地控制。
- 以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
List
接口中的方法超过了 Collection接口中指定的约定。- 包含Collection中继承的方法 + List接口中独有的方法
2.2 实现类
ArrayList【重点】
- 基于数组实现的
- 查询速度快,增删速度相对较慢
LinkedList
- 基于链表实现的
- 查询数据速度慢,增删数据速度快
Vector
- 基于数组 && 线程安全的
Vector
是同步的。
三、ArrayList
3.1 概述
List
- ArrayList容量可变,长度可变
- 基于数组实现
- 提供一些方法来操作内部用来存储列表的数组的大小。
- ensureCapacity(int minCapacity)
- 确保
ArrayList
的容量至少为指定的最小容量。这个方法主要是为了避免频繁的数组复制操作,因为ArrayList
在内部使用一个数组来存储元素,当数组空间不足时,会创建一个新的更大的数组并将原有元素复制过去,这是一个相对昂贵的操作。 - 参数
minCapacity
指定了ArrayList
应该至少具有的容量。如果当前的容量小于minCapacity
,那么ArrayList
会增加其内部数组的大小,以满足这个要求。
- 确保
- trimToSize
trimToSize()
方法是java.util.ArrayList
类的一个成员方法,它的作用是将ArrayList
的容量调整为其实际大小。在ArrayList
中,容量是指底层数组的大小,而大小则是指ArrayList
中实际元素的数量。- 通常,
ArrayList
在添加元素超过其当前容量时,会自动扩展其底层数组的大小,以容纳更多的元素。这种扩展通常是按照一定的比例进行的(默认是增加50%)。然而,这可能导致ArrayList
的容量远大于其实际大小,尤其是当你从一个较大的ArrayList
中移除大量元素后。 trimToSize()
方法的作用就在于此。当你调用trimToSize()
后,ArrayList
会重新分配一个刚好能容纳当前元素数量的新数组,并将所有元素复制到新数组中。这样,ArrayList
的容量就等于其大小,从而节省了内存。
- ensureCapacity(int minCapacity)
- 每个
ArrayList
实例都有一个容量。该容量是指用来存储列表元素的数组的大小。 - 它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。
- 在添加大量元素前,应用程序可以使用
ensureCapacity
操作来增加ArrayList
实例的容量。这可以减少递增式再分配的数量。
3.2 创建对象
import java.util.ArrayList;public class Demo01 {public static void main(String[] args) {/*** 构造方法摘要 ArrayList() 构造一个初始容量为 10 的空列表。 ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。 ArrayList(Collection<? extends E> c) 构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。 */// 构造一个初始容量为 10 的空列表。 ArrayList<String> list01 = new ArrayList<String>();// 构造一个具有指定初始容量的空列表。 ArrayList<String> list02 = new ArrayList<String>(1024);list02.add("Hello");list02.add("World");// 基于其他集合创建List集合对象,包含其他集合中的数据ArrayList<String> list03 = new ArrayList<String>(list02);System.out.println(list03);}
}
3.3 常用方法
增删
import java.util.ArrayList;public class Demo02 {public static void main(String[] args) {/**方法摘要 增boolean add(E e) 将指定的元素添加到此列表的尾部。 void add(int index, E element) 将指定的元素插入此列表中的指定位置。 boolean addAll(Collection<? extends E> c) 按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。 boolean addAll(int index, Collection<? extends E> c) 从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。 删E remove(int index) 移除此列表中指定位置上的元素。 boolean remove(Object o) 移除此列表中首次出现的指定元素(如果存在)。 void clear() 移除此列表中的所有元素。 removeAll移除两个集合中重复的内容*/// 创建集合ArrayList<String> list01 = new ArrayList<String>();// 添加数据list01.add("刘备");list01.add("刘封");list01.add("刘禅");list01.add("刘表");System.out.println(list01);// 在指定位置插入数据list01.add(2, "关羽");list01.add(2, "关羽");System.out.println(list01);// 通过索引移除数据,返回被移除的数据String name = list01.remove(0);System.out.println(name);System.out.println(list01);// 移除指定的对象,返回移除是否成功boolean result = list01.remove("关羽");System.out.println(result);System.out.println(list01);// 创建集合,存储整数ArrayList<Integer> list = new ArrayList<Integer>();// 添加数据list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);// 输出System.out.println(list);Integer i = 1;list.remove(i);System.out.println(list);}
}
改查
import java.util.ArrayList;
import java.util.List;public class Demo03 {public static void main(String[] args) {/*** 改E set(int index, E element) 用指定的元素替代此列表中指定位置上的元素。 void ensureCapacity(int minCapacity) 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。 void trimToSize() 将此 ArrayList 实例的容量调整为列表的当前大小。 查int size() 返回此列表中的元素数。 E get(int index) 返回此列表中指定位置上的元素。 boolean contains(Object o) 如果此列表中包含指定的元素,则返回 true。 containsAll是否包含另一个集合中的所有内容int indexOf(Object o) 返回此列表中首次出现的指定元素的索引,或如果此列表不包含该元素,则返回 -1。 int lastIndexOf(Object o) 返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含该索引,则返回 -1。 retainAll保留两个集合中的交集部分内容subList截取集合中的区间数据其他iteratorlistIteratorObject[] toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。 */// 创建集合ArrayList<String> list01 = new ArrayList<String>();// 添加数据list01.add("刘备");list01.add("刘封");list01.add("刘禅");list01.add("刘表");list01.add("关羽");list01.add("张飞");list01.add("赵云");System.out.println(list01);// 修改指定位置的元素list01.set(2, "刘阿斗");System.out.println(list01);// 元素的数量System.out.println(list01.size());// 获取指定索引位置的对象System.out.println(list01.get(0));System.out.println(list01.get(1));System.out.println(list01.get(2));System.out.println(list01.get(3));// 指定对象在集合中第一次出现的索引,如果对象不存在返回-1System.out.println(list01.indexOf("刘禅"));System.out.println(list01.indexOf("刘阿斗"));// 截取指定区间的数据,得到一个新的集合List<String> subList = list01.subList(2, 6);System.out.println(subList);}
}
3.4 遍历集合【重点】【掌握】
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;public class Demo04 {public static void main(String[] args) {/*** 遍历ArrayList集合* 索引遍历* for* while* do-while* 无索引遍历* foreach* iterator* listIterator*/// 创建集合ArrayList<String> list = new ArrayList<String>();// 添加数据list.add("刘备");list.add("关羽");list.add("张飞");list.add("赵云");list.add("黄忠");System.out.println("===============for==================");for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}System.out.println("===============while==================");int index = 0;while (index < list.size()) {System.out.println(list.get(index));index++;}System.out.println("===============do-while==================");index = 0;do {System.out.println(list.get(index));index++;} while (index < list.size());System.out.println("===============foreach==================");for (String name : list) {System.out.println(name);}System.out.println("===============iterator==================");// 获取迭代器对象Iterator<String> it = list.iterator();while (it.hasNext()) {String name = it.next();System.out.println(name);}System.out.println("===============listLterator==================");// 获取迭代器对象ListIterator<String> lit = list.listIterator();while (lit.hasNext()) {String name = lit.next();System.out.println(name);}while (lit.hasPrevious()) {String name = lit.previous();System.out.println(name);}System.out.println("----------------------------------------");// 从指定位置开始获取迭代器对象:开始的位置是最后一个元素ListIterator<String> litt = list.listIterator(list.size());// 逆序遍历集合while (litt.hasPrevious()) {String name = litt.previous();System.out.println(name);}}
}
3.5 比较ArrayList和LinkedList的性能
- 增加
- 查询
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class Demo05 {public static void main(String[] args) { // 创建集合 ArrayList<String> arrayList = new ArrayList<String>(); LinkedList<String> linkedList = new LinkedList<String>(); long arrayInsertStartTime = System.currentTimeMillis(); insertData(arrayList); long arrayInsertEndTime = System.currentTimeMillis(); System.out.println("ArrayList插入数据消耗时间:" + (arrayInsertEndTime-arrayInsertStartTime)); long linkedInsertStartTime = System.currentTimeMillis(); insertData(linkedList); long linkedInsertEndTime = System.currentTimeMillis(); System.out.println("LinkedList插入数据消耗时间:" + (linkedInsertEndTime- linkedInsertStartTime)); long arraySelectStartTime = System.currentTimeMillis(); selectData(arrayList); long arraySelectEndTime = System.currentTimeMillis(); System.out.println("ArrayList查询数据消耗时间:" + (arraySelectEndTime-arraySelectStartTime)); long linkedSelectStartTime = System.currentTimeMillis(); selectData(linkedList); long linkedSelectEndTime = System.currentTimeMillis(); System.out.println("LinkedList查询数据消耗时间:" + (linkedSelectEndTime-linkedSelectStartTime)); } /** * 插入数据100000条 * @param list */ public static void insertData(List<String> list) { for (int i = 0; i < 100000; i++) { list.add(0,Math.random() + ""); } } public static void selectData(List<String> list) { for (int i = 0; i < 100000; i++) { list.get(list.size()/2); } }}