java集合框架图
由上面的集合框架图可以看到,java集合框架主要包括两种类型的容器。
- 集合(Collection) 存储一个元素集合
- 图(Map) 存储键值对映射
Collection集合
集合概述
- 集合定义: 集合是java中提供的一种容器,可以用来存储多个数据。
- 集合和数组的区别:
- 数组的长度是固定的;集合长度是可变的。
- 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。
- Collection接口的子类型:
- List
- Set
- Queue
List集合
java.util.List 接口继承自 Collection 接口,是单列集合的一个重要分支,习惯性地会将实现了List 接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行 存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
List接口特点:
-
- 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
-
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
-
- 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
List接口常用方法:
-
public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
-
public E get(int index) :返回集合中指定位置的元素。
-
public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
-
public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
ArrayList集合
java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用 最多的功能为查询数据、遍历数据,所以 ArrayList 是最常用的集合。
ArrayList特点:
- ArrayList的底层是数组队列,相当于动态数组。它的容量能够动态增长。
- ArrayList提供了增删改查等功能。继承了AbstractList。
- ArrayList支持序列化,能够通过序列化去传输。实现了java.io.Serializable接口。
- ArrayList能被克隆。实现了Cloneable接口。
- ArrayList支持快速随机访问。实现了RandomAccess接口。
- ArrayList中的操作不是线程安全的。
ArrayList经典Demo:
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
System.out.println("Before add: "+arrayList.size());
arrayList.add(1);
arrayList.add(3);
arrayList.add(5);
arrayList.add(7);
arrayList.add(9);
arrayList.add(11);
System.out.println("After add: "+arrayList.size());
System.out.println("Printing elements of arrayList");
//一、通过迭代器
System.out.println("通过迭代器遍历:");
Iterator<Integer> it = arrayList.iterator();
while (it.hasNext()){
System.out.printf(it.next()+" ");
}
System.out.println();
//二、for i
System.out.println("通过索引值遍历:");
for (int i = 0; i < arrayList.size(); i++) {
System.out.printf(arrayList.get(i)+" ");
}
System.out.println();
//三、for each
System.out.println("通过for循环遍历:");
for (Integer number:arrayList) {
System.out.printf(number+" ");
}
System.out.println();
//toArray用法
//第一种
Integer[] integers = arrayList.toArray(new Integer[0]);
//第二种
Integer[] integers1 = new Integer[arrayList.size()];
arrayList.toArray(integers1);
System.out.println();
//在指定位置添加元素
arrayList.add(2,2);
//删除指定位置的元素
arrayList.remove(2);
//删除指定元素
arrayList.remove((Object)3);
//判断集合是否含有5
arrayList.contains(5);
//清空集合
arrayList.clear();
//判断集合是否为空
arrayList.isEmpty();
}
}
LinkedList集合
java.util.LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合。
LinkedList特点:
- LinkedList实现了List接口和Deque接口的双端链表。
- LinkedList底层的链表结构使得它具有高效的插入和删除操作。
- LinkedList具有队列特性。
- LinkedList不是线程安全的。
要使LinkedList线程安全方法:调用synchronizedList方法 Lisi list = Collections.synchronizedList(new LinkedList(...));
LinkedList常用方法:
- public void addFirst(E e) :将指定元素插入此列表的开头。
- public void addLast(E e) :将指定元素添加到此列表的结尾。
- public E getFirst() :返回此列表的第一个元素。
- public E getLast() :返回此列表的最后一个元素。
- public E removeFirst() :移除并返回此列表的第一个元素。
- public E removeLast() :移除并返回此列表的最后一个元素。
- public E pop() :从此列表所表示的堆栈处弹出一个元素。
- public void push(E e) :将元素推入此列表所表示的堆栈。
- public boolean isEmpty() :如果列表不包含元素,则返回true。
LinkedList经典Demo:
public class LinkedListDemo {
public static void main(String[] srgs) {
//创建存放int类型的linkedList
LinkedList<Integer> linkedList = new LinkedList<>();
/************************** linkedList的基本操作 ************************/
linkedList.addFirst(0); // 添加元素到列表开头
linkedList.add(1); // 在列表结尾添加元素
linkedList.add(2, 2); // 在指定位置添加元素
linkedList.addLast(3); // 添加元素到列表结尾
System.out.println("LinkedList(直接输出的): " + linkedList);
System.out.println("getFirst()获得第一个元素: " + linkedList.getFirst()); // 返回此列表的第一个元素
System.out.println("getLast()获得第最后一个元素: " + linkedList.getLast()); // 返回此列表的最后一个元素
System.out.println("removeFirst()删除第一个元素并返回: " + linkedList.removeFirst()); // 移除并返回此列表的第一个元素
System.out.println("removeLast()删除最后一个元素并返回: " + linkedList.removeLast()); // 移除并返回此列表的最后一个元素
System.out.println("After remove:" + linkedList);
System.out.println("contains()方法判断列表是否包含1这个元素:" + linkedList.contains(1)); // 判断此列表包含指定元素,如果是,则返回true
System.out.println("该linkedList的大小 : " + linkedList.size()); // 返回此 列表的元素个数
/************************** 位置访问操作 ************************/
System.out.println("-----------------------------------------");
linkedList.set(1, 3); // 将此列表中指定位置的元素替换为指定的元素
System.out.println("After set(1, 3):" + linkedList);
System.out.println("get(1)获得指定位置(这里为1)的元素: " + linkedList.get(1)); // 返回此列表中指定位置处的元素
/************************** Search操作 ************************/
System.out.println("-----------------------------------------");
linkedList.add(3); System.out.println("indexOf(3): " + linkedList.indexOf(3)); // 返回此列表 中首次出现的指定元素的索引
System.out.println("lastIndexOf(3): " + linkedList.lastIndexOf(3));// 返回此列表中最后出现的指定元素的索引
// /************************** Queue操作 ************************/
System.out.println("-----------------------------------------");
System.out.println("peek(): " + linkedList.peek()); // 获取但不移除此列表的头
System.out.println("element(): " + linkedList.element()); // 获取但不移除此列表的头
linkedList.poll(); // 获取并移除此列表的头
System.out.println("After poll():" + linkedList);
linkedList.remove();
System.out.println("After remove():" + linkedList); // 获取并移除此列表的头
linkedList.offer(4);
System.out.println("After offer(4):" + linkedList); // 将指定元素添加到此列 表的末尾
/************************** Deque操作 ************************/
System.out.println("-----------------------------------------");
linkedList.offerFirst(2); // 在此列表的开头插入指定的元素
System.out.println("After offerFirst(2):" + linkedList);
linkedList.offerLast(5); // 在此列表末尾插入指定的元素
System.out.println("After offerLast(5):" + linkedList);
System.out.println("peekFirst(): " + linkedList.peekFirst()); // 获取但不 移除此列表的第一个元素
System.out.println("peekLast(): " + linkedList.peekLast());// 获取但不移 除此列表的第一个元素
linkedList.pollFirst(); // 获取并移除此列表的第一个元素
System.out.println("After pollFirst():" + linkedList);
linkedList.pollLast(); // 获取并移除此列表的最后一个元素
System.out.println("After pollLast():" + linkedList);
linkedList.push(2); // 将元素推入此列表所表示的堆栈(插入到列表的头)
System.out.println("After push(2):" + linkedList);
linkedList.pop(); // 从此列表所表示的堆栈处弹出一个元素(获取并移除列表第一个元 素)
System.out.println("After pop():" + linkedList);
linkedList.add(3);
linkedList.removeFirstOccurrence(3); // 从此列表中移除第一次出现的指定元素(从 头部到尾部遍历列表)
System.out.println("After removeFirstOccurrence(3):" + linkedList);
linkedList.removeLastOccurrence(3); // 从此列表中移除最后一次出现的指定元素(从 尾部到头部遍历列表)
System.out.println("After removeFirstOccurrence(3):" + linkedList);
/************************** 遍历操作 ************************/
System.out.println("-----------------------------------------");
linkedList.clear(); for (int i = 0; i < 100000; i++) {
linkedList.add(i);
}
// 迭代器遍历
long start = System.currentTimeMillis();
Iterator<Integer> iterator = linkedList.iterator();
while (iterator.hasNext()) {
iterator.next();
}
long end = System.currentTimeMillis();
System.out.println("Iterator:" + (end - start) + " ms");
// 顺序遍历(随机遍历)
start = System.currentTimeMillis();
for (int i = 0; i < linkedList.size(); i++) {
linkedList.get(i);
}
end = System.currentTimeMillis();
System.out.println("for:" + (end - start) + " ms");
// 另一种for循环遍历
start = System.currentTimeMillis();
for (Integer i : linkedList) ;
end = System.currentTimeMillis();
System.out.println("for2:" + (end - start) + " ms");
// 通过pollFirst()或pollLast()来遍历LinkedList
LinkedList<Integer> temp1 = new LinkedList<>();
temp1.addAll(linkedList);
start = System.currentTimeMillis();
while (temp1.size() != 0) {
temp1.pollFirst();
}
end = System.currentTimeMillis();
System.out.println("pollFirst()或pollLast():" + (end - start) + " ms");
// 通过removeFirst()或removeLast()来遍历LinkedList
LinkedList<Integer> temp2 = new LinkedList<>();
temp2.addAll(linkedList);
start = System.currentTimeMillis();
while (temp2.size() != 0) {
temp2.removeFirst();
}
end = System.currentTimeMillis();
System.out.println("removeFirst()或removeLast():" + (end - start) + " ms");
}
}
Set集合
java.util.Set 接口和 java.util.List 接口一样,同样继承自 Collection 接口,它与 Collection 接口中的方法基本一致,并没有对 Collection 接口进行功能上的扩充,只是比 Collection 接口更加严格了。与 List 接口不同的是, Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
HashSet集合
java.util.HashSet 是 Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。 java.util.HashSet 底层的实现其实是一个 java.util.HashMap 支持。
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于: hashCode 与 equals 方法。
HashSet特点:
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化;
- HashSet不是同步的;
- 集合元素值可以是null;
LinkedHashSet集合
我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构。
TreeSet
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
内部存储机制
TreeSet内部实现的是红黑树,默认整形排序为从小到大。
TreeSet常用方法:
- Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回null;
- Object first():返回集合中的第一个元素;
- Object last():返回集合中的最后一个元素;
- Object lower(Object e):返回指定元素之前的元素。
- Object higher(Object e):返回指定元素之后的元素。
- SortedSet subSet(Object fromElement,Object toElement):返回此Set的子集合,含头不含尾;
- SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成;
- SortedSet tailSet(Object fromElement):返回此Set的子集,由大于fromElement的元素组成;
EnumSet
- EnumSet是一个专门为枚举类设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
- EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。
- EnumSet集合不允许加入null元素。
Queue
队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作。
Queue特点:
- 先进先出
- 线程安全 Queue常用操作:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞