Java 集合(超全)

集合框架分析

在这里插入图片描述

Java集合包含存储单值的Collection实现类(单列集合,有时直接说“集合”)和存储键值对的Map实现类(双列集合,映射)。

Collection类实现了Collection或其子接口,Map类同理。

AbstractCollection是抽象类,提供了Collection接口的一些实现,以最大限度地减少实现此接口所需的工作量。集合框架内其他抽象类作用类似。

Interface Collection

Collection接口继承了Iterable接口,还规定了以下方法:

方法描述
add(E e)返回boolean,表征是否插入成功
addAll(Collection<? extends E> c)可将指定集合中的所有元素添加到此集合中(可选)
clear()删除集合里的所有元素(可选)
contains(Object o)boolean
containsAll(Collection<?> c)
equals(Object o)
hashCode()
isEmpty()
iterator()返回此集合中元素的迭代器, Iterator
remove(Object o)boolean,只删除一个实例(可选)
removeAll(Collection<?> c)
retainAll(Collection<?> c)仅保留此集合中包含在指定集合中的元素(可选)
size()
toArray()Object[]
toArray(T[ ] a) T[] (指定了运行时类型)

还包含一些我暂不了解的方法:

方法描述
parallelStream()以此集合为源返回可能并行的流, default Stream
removeIf(Predicate<? super E> filter)删除此集合中满足给定谓词的所有元素
spliterator()在此集合中的元素上创建Spliterator
stream()返回以此集合为源的顺序流, default Stream
toArray(IntFunction<T[]> generator)返回包含此集合中所有元素的数组,使用提供的generator函数分配返回的数组

Collection主要有两个子接口:List(列表)、Set(集)。

List接口

在这里插入图片描述

规定可存储重复元素、元素有序的集合。

因为List是有序的,因而其额外规定了一些与索引有关的方法:如按索引查找、修改、添加、删除,返回符合某条件的索引等。

List可以提供一个特殊的迭代器:ListIterator,除了Iterator接口提供的正常操作外,还允许元素插入和替换以及双向访问。还提供了一种方法来获得从列表的指定位置开始的ListIterator。

以下是List增加的额外规定:

方法描述
add(int index, E element)一定会修改列表,所以返回void而不是boolean
addAll(int index, Collection<? extends E> c)void
get(int index)E
indexOf(Object o)返回此列表中指定元素第一次出现的索引,如果此列表中不包含该元素,则返回-1。
lastIndexOf(object o)int
listIterator()返回此列表中元素的列表迭代器(按适当顺序)
listIterator(int index)从列表的指定位置开始,~
of() of(E e1) … of(…E e10)返回包含0~10个元素的不可修改列表,static List
remove(int index)boolean
set(int index, E element)按索引替换,E(像缓存一样)
subList(int fromIndex, int toIndex)[ , ), List

暂不了解的方法:

方法描述
copyOf(Collection<? extends E> coll)以迭代顺序返回包含给定集合元素的unmodifiable List, static List
replaceAll(UnaryOperator operator)将该列表的每个元素替换为将运算符应用于该元素的结果, default void
sort(Comparator<? super E> c)根据指定的比较算子对此列表进行排列, default void

List实现类主要有:ArrayList, LinkedList, Vector。(使用比例可能为99%:1%:0)

ArrayList

数组列表,是由数组实现的列表。

默认数组长度为10,充满后还增加新的元素,会自动”扩容“。(动态数组+自动扩容)

因此,其特性为:

  • 易查找、修改;
  • 增加新元素代价大。

实现接口除List外,还有RandomAccess, Cloneable, Serializable。

注意,ArrayList不同步

  • 如果多个线程同时访问其实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。
  • 此类的…方法返回的2种迭代器是快速失败的

构造方法:

构造器参数描述
构造一个初始容量为10的空列表
int initialCapacity
Collection<? extends E> c按照集合的迭代器返回的顺序构造一个包含集合元素的列表

新增的方法(指相对于List接口,下同):

方法描述
clone()返回此数组列表实例的浅表副本,Object
ensureCapacity(int minCapacity)如有必要,增加此数组列表实例的容量,以确保它至少可以容纳参数指定的元素数
forEach(Consumer<? super E> action)
removeRange(int fromIndex, int toIndex)protected viod
trimToSize将此数组列表实例的容量调整为列表的当前大小,void
LinkedList

链接列表,由双向链表实现。因此,实现了一些对列表首、尾元素、相反顺序进行操作的方法。

因此,其特性为:

  • 增、删快,首、尾都快;
  • 查找、修改、遍历慢。

“大量的增加、删除操作是使用链接表的唯一理由”。

实现接口除List外,还有Deque, Cloneable, Seralizable。

注意,LinkedList不同步

  • 如果多个线程同时访问其实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。这通常通过同步自然封装列表的某个对象来完成。如果不存在此类对象,则应使用Collections.synchronizedList方法==“包装”==该列表。这最好在创建时完成,以防意外地不同步访问列表。
  • 同ArrayList,返回的迭代器是快速失败的。失败快速迭代器以尽力而为的方式抛出异常,因此,依赖于此异常的程序以确保其正确性是错误的。

允许所有元素,包括null。

构造方法:

构造器参数描述
构造一个空列表
Collection<? extends E> c

新增的方法:

方法描述
addFirst(E e), push(E e) 1.6void
addLast(E e)相当于add(E e), void
clone()返回浅表副本,Object
descendingIterator()以相反的顺序返回此双端队列中元素的迭代器, Iterator
getFirst(), element() 1.5E
getLast()E
offer(E e) 1.5将指定的元素添加为此列表的尾部,boolean(由Queue.offer(E)指定为true ?)
offerFirst(E e)boolean
offerLast(E e)boolean
peek() 1.5检索但不删除此列表的首部, 如果此列表为空,则返回null, E
peekFirst()检索但不删除此列表的首部,如果此列表为空,则返回null, E
peekLast()
poll() 1.5检索并删除此列表的首部,如果此列表为空,则返回null, E
pollFirst()检索并删除此列表的首部,如果此列表为空,则返回null, E
pollLast()
remove() 1.5检索并删除此列表的首部(空则抛异常), E
removeFirst(), pop() 1.6E
removeFirstOccurrence(Object o)删除此列表第一次出现的指定元素(从头到尾遍历列表时),boolean
removeLastE
removeLastOccurrence(Object o)boolean
Vector

向量,由数组实现。通过capacity和capacityIncrement来优化存储管理。

是线程安全的(同步的)。

现很少使用,一般用不同步的ArrayList。

实现的接口与ArrayList相同。

比ArrayList多一个构造方法:

构造器参数描述
int initialCapacity, int capacityIncrement构造具有指定初始容量和容量增量的空间向量

新增的方法:

方法描述
setSize(int newSize)
Set接口

在这里插入图片描述

规定不可存储重复元素、元素无序的集合。

最多1个null元素(某些禁止null作为元素)。

Set实现元素不可重复的原理是借助键值不可重复的Map。

如果将可变对象用作set元素,则必须非常小心。

元素无序指的是“存储元素的时间顺序与元素在数据结构中的位置顺序不一致”。

以下是Set的新增约定:

方法描述
copyOf(Collection<? extends E> coll)返回包含给定Collection的元素的unmodifiable集, static Set
of() of(E e1)…of(… E e10) of(E… elemnets)返回包含0、1、10、任意个元素的不可修改集, static Set

Set实现类主要有:HashSet和TreeSet。

HashSet

由哈希表(实际上是HashMap实例)支持。允许null元素。

存储结构为动态数组+链接表(桶内元素个数大于8->红黑树)。

查找一个元素,先求其在哪个桶里(对象数组的下标):hashCode()%容量,再在链表或红黑树里调用==equals(o)==方法找。

一旦把对象存入HashSet(或作为键存入HashMap),就不要再修改它。

其存储的对象必须重载hashCode()和equals()方法。

默认初始容量为16,默认加载因子为0.75.

再散列:已用空间 > 容量*负载因子时,将哈希表容量x2,重建哈希表。

  • 初始容量太大:浪费空间;太小:频繁散列,浪费时间。
  • 加载因子太大:查找慢;太小:浪费空间。

HashSet实现的接口除Set外,还有Cloneable, Serializable

此实现不同步。

  • 如果多个线程同时访问其实例,并且至少有一个线程在结构上修改了该集,则必须在外部进行同步。这通常通过同步自然封装集的某个对象来完成。如果不存在此类对象,则应使用Collections.synchronizedSet方法==“包装”==该集。这最好在创建时完成,以防意外地不同步访问。

    Set s = Collections.synchronizedSet(new HashSet(...));
    
  • 迭代器:快速失败、尽力而为。

构造方法:

构造器参数描述
int initialCapacity
int initialCapacity, float loadFactor
Collection<? extends E> c

部分方法(没什么新鲜的):

方法描述
add(E e)指定的元素不存在时,才会将其添加至此哈希集中,boolean
clone()返回浅表副本
contains(Object o)boolean
remove(Object o)boolean
TreeSet

(一个NavigableSet实现)基于一个TreeMap。采用有序的二叉树存放元素,默认顺序是自然顺序(对象实现Comparable接口的ComparaTo方法)。

add, remove, contains的时间复杂度是O(log(n))。

若存储自定义类型对象,则必须实现下面一个:

  • 该类实现java.lang.Comparable接口(实现compareTo(E e)方法,该方法返回int,返回0表征一样大)。
  • 创建树集时指定一个Comparator(接口的实现类),作为排序的比较器。

要维护比较器和equals方法的一致性

  • 这是因为Set接口是根据equals操作定义的,但是TreeSet实例使用其compareTo(或compare)方法执行所有元素比较。

树集就是通过比较器实现的元素唯一+有序存放

实现的接口有NavigableSet, Cloneable, Serializable。

此实现不同步。(细节和HashSet几乎一致,但包装应使用Collections.synchronizedSortedSet)

构造方法:

构造器参数描述
Collection<? extends E> c
Comparator<? super E> comparator创造一个新的空树集,根据制定的比较器进行排序
SortedSet s构造一个包含指定有序集相同元素并使用与其相同排序的新树集

新增的方法(与Set比较):

方法描述
clone()
first()返回第一个元素(最低元素),E
last()
ceiling(E e)返回此集中≥给定元素的最小元素,如果没有则返回null, E
floor(E e)
higher(E e)返回此集中>给定元素的最小元素,如果没有则返回null, E
lower(E e)
pollFirst()检索并删除第一个(最低)元素,集为空则返回null, E
descendingIterator()以降序返回迭代器, Iterator

暂不了解的方法:

方法描述
descendingSet()返回此集中包含的元素的逆序视图, NavigableSet
headSet(E toElement)返回此集的部分视图,其元素严格小于toElement, SortedSet
headSet(E toElement, boolean inclusive)返回此集的部分视图,其元素小于(或等于,如果inclusive为true)toElement, NavigableSet
tailSet(E fromElement)
tailSet(E from Element, bollean inclusive)
subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)NavigableSet
subSet(E fromElement, E toElement)SortedSet
Interface Map<K,V>

该接口规定的方法:

方法描述
clear() equals(Object o) hashCode() isEmpty() size()
containsKey(Object key)boolean
containsValue(Object value)boolean
copyOf(Map<? extends K, ? extends V> map)static <K,V> Map<K,V>
forEach(BiConsumer<? super K, ? super V> action)
get(Object key)V
getOrDefault(Object key, V defaultValue)返回映射到的值,如果此映射不包含键的映射则返回defaultValue,default V
keySet()Set
values()Collection
of() of(K k1, V v1)…of(…K k10, V v10)static <K,V> Map<K,V>
put(K key, V value)V
putAll(Map<? extends K, ? extends V> m)void
putIfAbsent(K key, V value)关联成功返回null,否则返回当前值, dafault V
remove(Object key)V
remove(Object key, Object value)仅当指定键当前映射到指定值时才删除,default boolean
replace(K key, V value)default V
replace(K key, V oldValue, V newValue)dafault boolean
replaceAll(BiFunction<? super K, ? super V, ? extends V> function)将每个条目的值替换为在该条目上调用给定函数的结果,default void

暂不了解的方法:

方法描述
compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)计算当前指定键及其当前映射值的映射, default V
merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)如果指定的键尚未与值关联(或映射到null),则将其与给定的非空值关联default V
computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)如果指定的键尚未与值关联(或映射到null),则使用给定的映射函数计算其值并将其输入此映射, default V
computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> mappingFunction)如果指定的键的值存在且不为null,则在给定键及其当前映射值的情况下计算其新映射,default V
entry(K k, V v)static <K,V> Map.Entry<K,V>
entrySet()Set<Map.Entry<K,V>>
ofEntries(Map.Entry<? extends K, ? extends V>… entries)返回包含从给定条目中提取的键和值的不可修改映射, static <K,V> Map<K,V>

Map的实现类主要有HashMap, WeakHashMap, Hashtable, TreeMap。

在这里插入图片描述

HashMap

实现接口Map<K,V>, Cloneable, Serializable。

基于哈希表实现。允许null值和null键。

HashMap大致相当于Hashtable,除了它是不同步的并且允许空值。

两个参数:初始容量负载因子。(默认16、0.75)

详见HashSet。

HashMap插入键值对的源码分析:

在这里插入图片描述

当键为实现Comparable接口的对象时,可以使用键之间的比较顺序来改善多键hashCode()相同带来的性能损耗。

此实现不同步。

  • ……Collections.synchronizedMap……
  • 迭代器快速失败、尽力而为。

构造方法:

构造器参数描述
int initialCapacity
int initialCapacity, float loadFactor
Map<? extends K, ? extends V> m
TreeMap

实现接口NavigableMap<K,V>, Cloneable, Serializable。

……详见TreeSet。

构造方法:

构造器参数描述
Comparator<? super K> comparator
Map<? extends K, ? extends V> m
SortedMap<K, ? extends V> m

新增方法(与Map比):

方法描述
descendingKeySet()NavigableSet
descendingMap()NavigableMap<K,V>
ceilingEntry(K key)Map.Entry<K,V>
floorEntry(K key)
higherEntry(K key)Map.Entry<K,V>
lowerEntry(K key)
firstEntry()Map.Entry<K,V>
lastEntry()
pollLastEntry()Map.Entry<K,V>
ceilingKey(K key)K
floorKey(K key)
higherKey(K key)K
lowerKey(K key)
firstKey()K
lastKey()
headMap(K tokey)SortedMap<K,V>
tailMap(K fromKey)
headMap(K toKey, boolean inclusive)NavigablrMap<K,V>
tailMap(K fromKey, boolean inclusive)
subMap(K fromKey, K toKey)SortedMap<K,V>
subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)NavigableMap<K,V>

时间顺序

JDK1.2出现Java Collections Framework, 其中Vector是由1.0版的Vector改进而来以实现List接口。部分集合也取代了之前的一些类。

Java5新增Collection第三个子接口:Queue(队列)。

更多框架图

每张图都不是最完善的,(可能是不重要的被省略了,也可能是版本更迭了),需要综合起来看。

在这里插入图片描述

在这里插入图片描述

放大局部:

在这里插入图片描述

综合点评

ArrayList是最常用的集合。允许null值。擅长随机访问。

LinkedList插入删除元素性能较好,还实现了Deque接口,可以当双端队列(含栈,队列)使用。

Vector与ArrayList类似,但是是同步的。

Stack是Vector的子类。

(尽量避免在关键属性将来有可能被修改的情况下使用set和 map)

HashSet是Set最常用的实现类,是其经典实现。集合元素值可以为null。

LinkedHashSet是HashSet的子类,由于其需要维护元素的插入顺序(链接表+哈希表),因此性能略低于HashSet,但在遍历时有很好的性能。

TreeSet是SortedSet接口的实现类,保证元素处于排序状态。

EnumSet是一个专为枚举类(元素只能是同一个枚举类的枚举值)设计的集合类,不允许添加null值。元素也是有序的(枚举值在Enum类内的定义顺序)。

综合性能:EnumSet > HashSet > LinkedHashSet > TreeSet

HashMap\LinkedHashMap\TreeMap\EnumMap的比较类似Set。

(HashMap与Hashtable的关系完全类似于ArrayList和Vector)

所有集合类都位于java.util包下,但支持多线程的集合类位于java.util.concurrent包下。(比如java.util.Hashtable(独占锁)虽然也是线程安全的,但java.util.concurrent.ConcurrentHahMap(分段锁)效率更高)

Iterator接口和ListIterator接口

Iterator是一个接口,它是集合的迭代器。集合可以通过Iterator去遍历集合中的元素。Iterator提供的API接口如下:

♦ boolean hasNext():判断集合里是否存在下一个元素。如果有,hasNext()方法返回 true。
  ♦ Object next():返回集合里下一个元素。
  ♦ void remove():删除集合里上一次next方法返回的元素。

ListIterator接口继承Iterator接口,提供了专门操作List的方法。ListIterator接口在Iterator接口的基础上增加了以下几个方法:

♦ boolean hasPrevious():判断集合里是否存在上一个元素。如果有,该方法返回 true。
  ♦ Object previous():返回集合里上一个元素。
  ♦ void add(Object o):在指定位置插入一个元素。

以上两个接口相比较,不难发现,ListIterator增加了向前迭代的功能(Iterator只能向后迭代),ListIterator还可以通过add()方法向List集合中添加元素(Iterator只能删除元素)。

Collections

集合工具类:提供搜索、排序、视图等面向集合的静态方法。

如,排序:static void sort(List list, Comparator<? super T> c)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值