Java 容器

概述

Java 的集合框架大致分为 Collection 和 Map 两种,两者区别:

  • Collection 是单元素集合;Map 是双元素键值对集合;
  • Collection 中只有 Set 系列要求元素唯一;Map 中要求键唯一,值可以重复;
  • Collection 的数据结构是针对元素的;Map 的数据结构是针对键的。


Collection 集合

i 标识的是 Collection 派生出的子接口,c 标识是实现类。


Collection

Collection 接口是 Set、List 和 Queue 接口的父接口,该接口定义的方法既可以用于操作 Set 集合,也可用于操作 List 和 Queue 集合。

//向集合添加一个元素,成功返回true
boolean add(E e);

//把集合c的全部元素添加入指定集合,成功返回true
boolean addAll(Collection<E> c);

//删除集合中指定元素o,当集合中包含一个或多个元素o时,只删除第一个
boolean remove(E o);

//从集合中删除集合c里包含的所有元素(相当于调用该集合减集合c)
boolean removeAll(Collection<E> c);

//集合里是否包含指定元素
boolean contains(E o);

//集合里是否包含集合c里的所有元素
boolean containsAll(Collection<E> c);

//返回集合里元素的个数
int size();

//清除集合里的所有元素,将集合长度变为0
void clear();

//返回Iterator对象,用于遍历集合中的元素
Iterator<E> iterator();

//从集合中删除集合c里不包含的元素(相当于取该集合和集合c的交集)
boolean retainAll(Collection<E> c);

//该方法把集合转换成一个数组,所有集合元素变成数组元素,一般不推荐使用这个方法
Object[] toArray();

//该方法把集合转换成一个数组,传入的参数一般为类型为 T 长度为 0 的空数组,推荐使用
//例如:Integer[] newText = c.toArray(new Integer[0]);
<T> T[] toArray(T[] a);

//该方法是Java 8为Map新增的一个遍历key-value对的方法,使用Lambda表达式
void forEach(BiConsumer action);

//Java 8新增,将集合转换为Stream流
void forEach(Consumer<? super T> action)

Set

  • TreeSet:基于红黑树实现,支持有序性操作,在增加和删除数据上特别高效。查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)
  • HashSet:基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。
  • LinkedHashSet:是 HashSet 的子类,在 HashSet 基础上使用双向链表维护元素的插入顺序。

Set 作为 Collection 接口的子接口,可以使用 Collection 接口里的全部方法。


List

  • ArrayList:基于动态数组实现,所以查询速度快,增删速度慢。
  • Vector:和 ArrayList 功能类似,是线程安全的。
  • Stack:栈数据结构,是 Vector 的子类,因此也是线程安全的。
  • LinkedList:基于双向链表实现,只能顺序访问,所以查询特别慢,但是可以快速地在链表中间插入和删除元素。因为 LinkedList 还实现了 Queue 接口,所以还可以用作栈、队列和双向队列。

注意:vector 和 Stack 过于古老,性能不佳,不推荐使用。栈操作一般使用 ArrayDeque 来代替。

List 作为 Collection 接口的子接口,可以使用 Collection 接口里的全部方法。另外,由于 List 是有序集合,所以添加了根据索引来插入、替换和删除集合元素的方法。

//将元素 element 添加到 List 集合索引 index 处,原 index 及后续的元素往后移动 
void add(int index, E element);

//将 Collection 集合中的所有元素插入到 List 集合的 index 处。
boolean addAll(int index, Collection<? extends E> c);

//删除并返回 index 索引处的元素
E remove(int index);

//返回索引 index 处的元素。
E get(int index);

//将位置索引为 index 的元素,替换为 element。
E set(int index, E element);

//返回元素 o 在 list 集合中第一次出现的位置索引。  
int indexOf(E o);

//返回元素 o 在 List 集合中最后一次出现的位置索引。  
int lastIndexOf(E o);

//返回 List 集合中从索引fromIndex (包含)到索引 toIndex(不包含)之间的所有元素。
List<E> subList(int fromIndex, int toIndex);

//Java 8新增根据 operator 指定的计算规则来重新设置 List 集合的所有元素。
void replaceAll(UnaryOperator<E> operator);

//Java 8新增根据 Comparator 参数对 List 集合的元素排序。
void sort(Comparator<? super E> c);

Queue

  • PriorityQueue:优先级队列,基于堆结构实现。
  • ArrayDeque:双端队列,基于一个动态数组实现,常用来代替 Vector 的栈操作。
  • LinkedList:双端队列,基于一个双向链表实现。

Queue 作为 Collection 接口的子接口,可以使用 Collection 接口里的全部方法。另外,由于 Queue 是队列集合,所以添加了根据队列特性来插入、替换和删除集合元素的方法。

//将指定元素插入到队列的尾部。
boolean add(E e);

//获取队列头部的元素,并删除该元素。
E remove();

//获取队列头部的元素,但是不删除该元素。
E element();

//将指定的元素插入此队列的尾部。当使用容量有限的队列时,此方法通常比add(Object e)有效。
boolean offer(E e);

//返回队列头部的元素,并删除该元素。如果队列为空,则返回null。
E poll();

//返回队列头部的元素,但是不删除该元素。如果队列为空,则返回null。
E peek();

Deque 是 Queue 接口的子接口,它是一个双端队列,既可以当队列用,也可以当栈用。如果 Deque 当做常规的队列用使用,最左端(如果以数组存储,就是第一个元素)是队头,最右端是队尾;当成常规的栈用,最左端是栈顶,最右端是栈底。Deque 根据双端队列的特性也定义了一些方法:

//将指定元素添加到双端队列的头部。
void addFirst(E e);

//将指定元素添加到双端队列的尾部。
void addLast(E e);

//将指定元素添加到双端队列的头部。
boolean offerFirst(E e);

//将指定元素添加到双端队列的尾部。
boolean offerLast(E e);

//获取但不删除双端队列的第一个元素(头)。
E getFirst();

//获取但不删除双端队列的最后一个元素(尾)。
E getLast();

//获取但不删除双端队列的第一个元素;如果双端队列为空,则返回null。
E peekFirst();

//获取但不删除双端队列的最后一个元素;如果双端队列为空,则返回null。
E PeekLast();

//获取并删除双端队列的第一个元素;如果双端队列为空,则返回null。
E pollFirst();

//获取并删除双端队列的最后一个元素;如果双端队列为空,则返回null。
E pollLast();    

//获取并删除该双端队列的第一个元素。
E removeFirst();

//获取并删除该双端队列的最后一个元素o。
E removeLast();

//pop出该双端队列所表示的栈的栈顶元素。相当于removeFirst()。
E pop(); //(栈方法)

//将一个元素push进该双端队列所表示的栈的栈顶。相当于addFirst()。
void push(E e); //(栈方法): 
  • Deque 的方法与 Queue 的方法对比
Queue 的方法 Deque 的方法
add(e)/offer(e) addLast(e)/offerLast(e)
remove()/poll() removeFirst()/pollFirst()
element()/peek() getFirst()/peekFirst()

Deque 也可以直接使用 offer(e) 和 poll() 方法实现入队和出队,用 peek() 访问队头,

  • Deque 的方法与 Stack 的方法对比
Stack 的方法 Deque 的方法
push(e) addFirst(e)/offerFirst(e)
pop() removeFirst()/pollFirst()
peek() getFirst()/peekFirst()

Deque 也可以直接使用 push(e) 和 pop() 方法实现入栈和出栈,用 peek() 访问栈顶。



Map 集合

i 标识的是 map 派生出的子接口,c 标识是实现类。

  • TreeMap:基于红黑树实现。

  • HashMap:基于哈希表实现。

  • LinkedHashMap:是 HashMap 的子类,在 HashMap 基础上使用双向链表维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。

  • HashTable:和 HashMap 类似,是线程安全的。

注意:HashTable 是一个古来的遗留类,不应该去使用它。现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁。


Map接口方法

//添加一个key-value对,如果当前Map中已有一个与该key相等的key-value对,
//则新的key-value会覆盖原来的key-value对。
V put(K key, V value);

//将指定Map中key-value复制到当前Map中。
void putAll(Map<? extends K, ? extends V> m);

//返回指定的key所对应的value;如果此Map中不包括该key,则返回null。
V get(Object key);

//返回指定的key所对应的value;如果此Map中不包括该key,则返回defalutValue。
V getOrDefault(Object key, V defaultValue);

//删除指定key所对应的key-value对,返回被删除key所对应的value,如果key不存在返回null。
V remove(Object key);

//删除指定key,value所对应的key-value对。如果成功删除,则返回true,否则返回false。
boolean remove(Object key, Object value);

//查询Map集合中是否包含指定的key,如果包含,返回true。
boolean containsKey(object key);

//查询Map集合中是否包含指定的value,如果包含返回true。
boolean containsValue(Object value);

//返回该map中所有key所组成的集合。
Set<K> keySet();

//返回Map中包含的key-value对所组成的Set集合,
//每个集合元素都是Map.Entry(Entry是Map的内部类,用于存储key-value的)对象。
Set<Map.Entry<K, V>> entrySet();

//返回该Map中key-value的个数。
int size();

//删除Map集合中的所有key-value对。
void clear();

//查询该Map是否为空,如果为空则返回null。
boolean isEmpty();

//返回该Map中所有value组成的collection。
Collection<V> values();

//该方法是Java8为Map新增的一个遍历key-value对的方法,使用Lambda表达式。
void forEach(BiConsumer<? super K, ? super V> action)

//Java 8新增,将Map中指定key对应的value替换成新value。
//如果key在Map中不存在,该方法不会添加key-value对,而是返回null。
V replace(K key, V value);

//Java 8新增,将Map中指定的key-value对的原value替换成新value。
//如果在Map中找到指定的key-value对,则执行替换并返回true,否则返回false。
boolean replace(K key, V oldValue, V newValue);

内部类Map.Entry

Map 中包含一个内部类 Map.Entry<K, V>,该类用来封装 key-value 对。Map 接口的 entrySet() 方法返回所有 Map.Entry 所组成的 Set 集合。该类方法如下:

//返回该Entry里包含的key值
K getKey();

//返回该Entry里包含的value值
V getValue();

//设置该Entry里包含的value值,并返回新设置的value值
V setValue(V value);


参考

  1. https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20%E5%AE%B9%E5%99%A8.md
  2. <<疯狂 Java 讲义>>
原文地址:https://www.cnblogs.com/zongmin/p/11350844.html