Java集合类梳理

集合框架

在这里插入图片描述
在这里插入图片描述

Collection

Collection 接口用于表示任何对象或元素组。它是 List 和 Set 的父接口。

Collection 声明的方法:

点击查看方法摘要

List

List集合代表一个有序、可变长、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合默认按照元素的添加顺序设置元素的索引,可以通过索引(类似数组的下标)来访问指定位置的集合元素。

List相当于下图的格子,按顺序放入值,for循环可以挨个取出:
在这里插入图片描述

实现List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

特点梳理:

  • List集合为列表类型,以线性方式,有序存取对象。各元素的顺序就是对象插入时的顺序,即元素按进入先后有序保存。

  • List集合有序是指存储的元素有下标,下标从0开始,以1递增。所以可以通过使用索引来访问List集合中的元素,即可以用下标进行元素的操作

  • List集合中的元素允许重复,即可以存储重复的元素。

List常用方法

点击查看方法摘要

ArrayList

ArrayList是一个动态数组,也是我们最常用的集合,是List类的典型实现。它允许任何符合规则的元素插入甚至包括null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。

在这里插入图片描述

如上图,ArrayList若要找Killer,则要通过for循环,从Tom开始挨个找才能找到,ArrayList的查询速度比LinkedList快,但不及HashMap快。数据若是很庞大,而且又频繁查找的业务,建议使用散列表。

特点梳理:

  • 底层数据结构是数组,添加、查找、删除均采用基本数组操作,可以存储重复元素

  • 查找效率高,添加、删除效率低,整体效率高

  • 初始大小10,最大容量Integer.MAX_VALUE - 8

  • 满时扩容,扩容大小为1.5倍,(int newCapacity = oldCapacity + (oldCapacity >> 1)。

  • 采用Arrays.copyOf()产生新数组

  • 没有同步,线程不安全

ArrayList常用方法

点击查看方法摘要

LinkedList

LinkedList 是List 接口的另一个实现类,除了可以根据索引访问集合元素外,LinkedList 还实现了 Deque 接口,可以当作双端队列来使用,也就是说,既可以当作“栈”使用,又可以当作队列使用。

LinkedList 的实现机制与 ArrayList 的实现机制完全不同,ArrayList 内部以数组的形式保存集合的元素,所以随机访问集合元素有较好的性能;LinkedList 内部以链表的形式保存集合中的元素,所以随机访问集合中的元素性能较差,但在插入删除元素时有较好的性能。

特点梳理:

  • 同时实现了Queue和Deque接口

  • 底层采用双向链表实现,头结点不存放数据,允许为null
    在这里插入图片描述

  • 只要是遍历链表就需要使用 ListIterator

  • 索引优化,可以根据 index 可以选择从 first 和 last 开始遍历

  • 线程不安全

LinkedList常用方法

点击查看方法摘要

Vector

与 ArrayList 相似,但是 Vector 是同步的。所以说 Vector 是线程安全的动态数组。它的操作与 ArrayList 几乎一样。

Vector 类实现了可扩展的对象数组。 像数组一样,它包含可以使用整数索引访问的组件。 但是, Vector 的大小可以根据需要增长或缩小,以适应在创建 Vector 之后添加和删除项目。

特点梳理:

  • 底层由数组实现,添加、查找、删除均采用基本数组操作,所以查找效率高,添加、删除效率低

  • 初始大小10,最大容量 Integer.MAX_VALUE - 8

  • 满时扩容,扩容大小为1.5倍,(int newCapacity = oldCapacity + (oldCapacity >> 1)

  • 采用 Arrays.copyOf() 产生新数组

  • 线程不安全

Vector 常用方法

点击查看方法摘要

Stack

Stack 继承自 Vector,实现一个后进先出的堆栈。Stack 提供5个额外的方法使得 Vector 得以被当作堆栈使用。基本的 push 和 pop 方法,还有 peek 方法得到栈顶的元素,empty 方法测试堆栈是否为空,search 方法检测一个元素在堆栈中的位置。Stack 刚创建后是空栈。

在这里插入图片描述

Stack 常用方法

点击查看方法摘要

Set

继承自 Collection 接口,且方法相同,Set 没有在 Collection 的基础上进行功能的扩展,只是比Collection 接口更加严格了,Set 接口是无序的。

Set集合的实现类可说是基于Map集合去写的。通过内部封装Map集合来实现的比如HashSet内部封装了HashMap。

Set相当于往袋子里放东西,无序取出(使用迭代器取出),如下图:
在这里插入图片描述

特点梳理:

  • 继承自Collection

  • Set集合中的元素无序,即插入无序

  • 不可指定位置访问,即没有索引值

HashSet

HashSet是Set集合最常用实现类,是其经典实现。HashSet是按照hash算法来存储元素的,因此具有很好的存取和查找性能。

HashSet使用HashMap的数据结构,仅使用HashMap中的key结构,value值一律为null。也就是说真实数据存储在 HashMap 的 key 列,value 列全部为空。

HashSet 存储原理:

当向 HashSet 集合存储一个元素时,HashSet 会调用该对象的 hashCode() 方法得到其 hashCode 值,然后根据 hashCode 值决定该对象的存储位置,

HashSet 集合判断两个元素相等的标准是:

  1. 两个对象通过 equals() 方法比较返回 true
  2. 两个对象的hashCode()方法返回值相等。

因此,如果(1)和(2)有一个不满足条件,则认为这两个对象不相等,可以添加成功。如果两个对象的 hashCode() 方法返回值相等,但是两个对象通过 equals() 方法比较返回 false,HashSet会以链式结构将两个对象保存在同一位置,这将导致性能下降,因此在编码时应避免出现这种情况。

HashSet 查找原理:

基于 HashSet 以上的存储原理,在查找元素时,HashSet 先计算元素的 HashCode 值(也就是调用对象的 hashCode 方法的返回值),然后直接到 hashCode 值对应的位置去取出元素即可,这就是 HashSet 速度很快的原因。

重写 hashCode() 方法的基本原则:

  1. 在程序运行过程中,同一个对象的hashCode()方法返回值应相同。
  2. 当两个对象通过equals()方法比较返回true时,这两个对象的hashCode()方法返回值应该相等。
  3. 对象中用作equals()方法比较标准的实例变量,都应该用于计算hashCode值。

特点梳理:

  • 不能保证元素的顺序

  • HashSet不是线程同步的,如果多线程操作HashSet集合,则应通过代码来保证其同步

  • 集合元素值可以是null

HashSet 常用方法

点击查看方法摘要

LinkedHashSet

LinkedHashSet 是 HashSet 的一个子类,具有 HashSet 的特性,也是根据元素的 hashCode 值来决定元素的存储位置。但它使用链表维护元素的次序,元素的顺序与添加顺序一致。由于 LinkedHashSet 需要维护元素的插入顺序,因此性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

LinkedHashSet 是一个非线程安全的集合。如果有多个线程同时访问当前 LinkedHashSet 集合容器,并且有一个线程对当前容器中的元素做了修改,那么必须要在外部实现同步保证数据的冥等性。

特点梳理:

  • LinkedHashSet的底层使用LinkedHashMap存储元素

  • LinkedHashSet是有序的,它是按照插入的顺序排序的

  • LinkedHashSet 是一个非线程安全的集合

LinkedHashSet 常用方法

点击查看方法摘要

TreeSet

TreeSet 是 SortedSet 接口的实现类,TreeSet可以保证元素处于排序状态,它采用红黑树的数据结构来存储集合元素。TreeSet 支持两种排序方法:自然排序和定制排序,默认采用自然排序。

排序:

当向TreeSet中添加自定义对象时,有 2 种排序方法:

  1. 自然排序

要求自定义类实现 java.lang.Comparable 接口并重写 compareTo(Object obj) 方法。在此方法中,指明按照自定义类的哪个属性进行排序

  1. 定制排序

当元素不具备比较性时,此时只能为容器添加比较器来解决问题,即创建 TreeSet 时向其中加入Comparator

特点梳理:

  • 有序

  • 不可重复

  • 红黑树

  • 基于Treemap实现

  • 自定义排序等特点

  • 非线程安全

  • TreeSet中存储的类型必须是一致的,不能一下存 int,一下又存 String

TreeSet常用方法

点击查看方法摘要

EnumSet

EnumSet 是一个专为枚举类设计的集合抽象类,EnumSet 中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。不允许添加 null 值。EnumSet 的集合元素也是有序的,它以枚举值在 Enum 类内的定义顺序来决定集合元素的顺序。

特点梳理:

  • EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序

  • EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此 EnumSet 对象占用内存很小,而且运行效率很好。尤其是进行批量操作(如调用containsAll()和retainAll()方法)时,如果其参数也是EnumSet集合,则该批量操作的执行速度也非常快

  • EnumSet 集合不允许加入 null 元素,如果试图插入 null 元素,EnumSet 将抛出 NullPointerException 异常

  • EnumSet 类没有暴露任何构造器来创建该类的实例,程序应该通过它提供的类方法来创建 EnumSet 对象

  • 如果只是想判断 EnumSet 是否包含 null 元素或试图删除 null 元素都不会抛出异常,只是删除操作将返回false,因为没有任何 null 元素被删除。

EnumSet 常用方法

点击查看方法摘要

Map

Map 接口采用键值对 Map<K,V> 的存储方式,保存具有映射关系的数据,因此,Map 集合里保存两组值,一组值用于保存 Map 里的 key,另外一组值用于保存 Map 里的 value,key 和 value 可以是任意引用类型的数据。key 值不允许重复,可以为 null。如果添加 key-value 对时 Map 中已经有重复的 key,则新添加的 value 会覆盖该 key 原来对应的 value。常用实现类有 HashMap、LinkedHashMap、TreeMap等。

Map 声明的方法:

点击查看方法摘要

HashMap

HashMap 基于 hashing 原理,通过 put() 和 get() 方法存储和获取对象。当我们将键值对传递给 put() 方法时,它调用键(key)对象的 hashCode() 方法来计算 hashCode 值,然后找到对应的 bucket 位置来储存值(value)对象。当获取对象时,通过键(key)对象的 equals() 方法找到正确的键值对,然后返回对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会存储在链表的下一个节点中。

原理图 1:

在这里插入图片描述
注:JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

原理图 2:
在这里插入图片描述
原理图 3:
在这里插入图片描述
如上“原理图 3”,散列表中有散列数组,散列数组存放的元素是线性表(散列桶)。往散列表存放数据是键值对放进去,“Mac”和“Jerry”的HashCode一样,所以计算出来的散列值一样,假设该散列值计算得到的下标是2,就将“Mac”和“Jerry”存放在散列数组下标为2的这个散列桶里。而“Andy”的散列值计算得到的下标是8,那么“Andy”就保存在下标为8的散列桶里。由于所存放的数据只在下标为2和8的散列桶中,所以散列数组中其它位置则为空值。要找25这个元素,只要计算“Jerry”的散列值,最后计算得到下标2,然后在对应的散列桶中依次查找“Jerry”,就可以找到对应的25。

其实真正意义上的散列表如下图所示,以上“原理图”只是说明原理罢了,使用HashMap时将其想象成多行两列的表格即可。
在这里插入图片描述

真正存取的有意义的元素是key值所对应的value值,key值只不过是value值所取的名字,为了方便以后的查找之用。

特点梳理:

  • 底层采用哈希表+链表或红黑树实现。

  • 哈希表初始容量 1<<4,最大容量 1<<30,默认负载因子0.75f。

  • 阈值为负载因子*容量,到达阈值时扩容,扩容为两倍,或者在最开始的时候,这是为了如果预计Hashmap会很大,可以把初始值调大。

  • 当一个桶的节点数大小到达 8,开始从链表转换为红黑树。当一个红黑树大小到达 6,退化为链表。

  • 线程不安全

HashMap 常用方法

点击查看方法摘要

Hashtable

HashMap 与 Hashtable 是 Map 接口的两个典型实现,它们之间的关系完全类似于 ArrayList 与 Vertor。HashTable 是一个古老的 Map 实现类,它提供的方法比较繁琐,目前基本不用了。

原理图:

在这里插入图片描述

LinkedHashMap

对于 LinkedHashMap 而言,它继承自 HashMap,底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似。LinkedHashMap 使用双向链表来维护 key-value 对的次序(其实只需要考虑 key 的次序即可),该链表负责维护 Map 的迭代顺序,默认与插入顺序一致(默认情况,遍历时的顺序是按照插入节点的顺序),即在每次插入数据,或者访问、修改数据时,会增加节点、或调整链表的节点顺序,以决定迭代时输出的顺序。

可以在构造时传入 accessOrder 参数,使得其遍历顺序按照访问的顺序输出。

原理图:

在这里插入图片描述

特点梳理:

  • 继承自HashMap

  • 额外使用类似于LinkedList的双向链表,维护插入顺序

  • 线程不安全,效率高

  • 键和值都可以是 null

  • 底层由双向链表和哈希表组成

  • 键元素:唯一(由哈希表结构保证)、有序(按照录入顺序,由链表结构保证)

LinkedHashMap 的常用方法

点击查看方法摘要

TreeMap

TreeMap 是 SortedMap 的实现类,是一个红黑树的数据结构,每个 key-value 对作为红黑树的一个节点。TreeMap 存储 key-value 对时,需要根据 key 对节点进行排序。

TreeMap 继承自 AbstractMap,实现了 Map, Cloneable, NavigableMap, Serializable 接口:

  1. TreeMap 继承于 AbstractMap,而 AbstractMap 实现了 Map 接口,并实现了 Map 接口中定义的方法,减少了其子类继承的复杂度

  2. TreeMap 实现了 Map 接口,成为 Map 框架中的一员,可以包含着 key-value 形式的元素

  3. TreeMap 实现了 NavigableMap 接口,意味着拥有了更强的元素搜索能力

  4. TreeMap 实现了 Cloneable 接口,实现了 clone() 方法,可以被克隆

  5. TreeMap 实现了 Java.io.Serializable 接口,支持序列化操作,可通过 Hessian 协议进行传输

特点梳理:

  • 底层采用红黑树实现

  • 保存的元素按照一定的规则有序

  • 可以传入比较器,即可自定义排序规则,不然就按照key排序

  • 非线程安全

TreeMap 常用方法

点击查看方法摘要

TreeMap 排序方式

  • 自然排序:TreeMap 的所有 key 必须实现 Comparable 接口,而且所有的 key 应该是同一个类的对象,否则会抛出ClassCastException。

  • 定制排序:创建TreeMap时,传入一个Comparator对象,该对象负责对TreeMap中的所有key进行排序。

WeakHashMap

WeakHashMap 继承于AbstractMap,实现了Map接口。和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null。不过WeakHashMap的键是“弱键”。在 WeakHashMap 中,当某个键不再正常使用时,会被从WeakHashMap中被自动移除。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。某个键被终止时,它对应的键值对也就从映射中有效地移除了。

这个“弱键”的原理呢?大致上就是,通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。实现步骤是:

  1. 新建WeakHashMap,将“键值对”添加到WeakHashMap中。
    实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。

  2. 当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到ReferenceQueue(queue)队列中。

  3. 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对;同步它们,就是删除table中被GC回收的键值对。
    这就是“弱键”如何被自动从WeakHashMap中删除的步骤了。

WeakHashMap 常用方法

点击查看方法摘要

IdentityHashMap

IdentityHashMap 比较 key 时是“引用相等”,即对于 k1 和 k2,当k1 == k2 时,IdentityHashMap 认为两个key相等。

IdentityHashMap 允许使用 null 作为 key 和 value.,不保证任何 Key-value 对之间的顺序, 更不能保证他们的顺序随时间的推移不会发生变化。

IdentityHashMap 有其特殊用途,比如序列化、深度复制、记录对象代理等。

IdentityHashMap 常用方法

点击查看方法摘要

EnumMap

Map 接口的实现,其 key-value 映射中的 key 是 Enum 类型。其原理就是一个对象数组,数组的下标索引就是根据 Map 中的 key 直接获取,即枚举中的 ordinal 值。效率比 HashMap 高,可以直接获取数组下标索引并访问到元素。

EnumMap 常用方法

点击查看方法摘要

Properties

Properties 类是 Hashtable 类的子类,它相当于一个 key、value 都是 String 类型的 Map ,主要用于读取配置文件。

Properties 常用方法

点击查看方法摘要

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值