一、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("白龙马");
/**
* foreach
for(数据类型 变量名 : 容器对象){
}
容器对象:
数组、集合
数据类型:
容器中元素的类型
变量名字:
临时变量名字,用来存储容器中的每一个元素
*/
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
截取集合中的区间数据
其他
iterator
listIterator
Object[] 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));
// 指定对象在集合中第一次出现的索引,如果对象不存在返回-1
System.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);
}
}
}