|
前言
作者简介: 不肯过江东丶,一个来自二线城市的程序员,致力于用“猥琐”办法解决繁琐问题,让复杂的问题变得通俗易懂。 支持作者: 点赞 、关注 、留言 ~ Java 提供了大量优秀的集合实现供开发者使用,作为一名合格的程序员,我们必须要能够通过功能场景和性能需求选用最合适的集合,这也就要求开发者必须熟悉 Java 的常用集合类;除此之外,在我们面试的过程中也常常被问到关于集合的一些知识点,这也同样证明了集合的重要性,那么今天就给大家汇总一下我们常用到的集合以及各个集合的相关特点。
常见的集合及其特点
Java 中提供的众多集合类由两大接口衍生而来,分别是 Collection 接口和 Map 接口:
Collection 接口:它定义了一个包含一批对象的集合,其中包含的方法有很多,比如:size()、add()、addAll()、remove()、removeAll() 等等
Map 接口:它在 Collection 的基础上,为其中的每个对象指定了一个键(Key),并使用 Entry 保存每个键值对(Key - Value),通过键值对的保存形式可以让我们通过 Key 快速找到所需的 Value 值。Map接口的主要方法包括:size()、put()、putAll()、get() 等等 我们对这两大接口做了一个简单的了解,接下来我们再看看通过这两大接口衍生出来的集合类。
List 类的集合
List 作为 Collection 的子接口,它用于定义以列表形式存储的集合,List 接口为集合中的每个对象分配了一个索引(index),通过索引来标记该对象在 List 中的位置,并可以通过索引定位到指定位置的对象。它不但继承了 Collection 接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,比如:
- public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上
- public E get(int index) :返回集合中指定位置的元素
- public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素
- public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素
接下来我们再看看 List 接口下的常用实现类
ArrayList 集合
ArrayList 基于数组来实现集合的功能,其内部维护了一个可变长的数组,集合内所有元素都存储在这个数组中,并且该数组的长度可以动态进行伸缩。同时 ArrayList 实现了 Cloneable 接口与 java.io.Serializable 接口,也就意味着 ArrayList 可以支持克隆和序列化。其常用的方法如下:
- add():添加一个元素
- get():取出集合中的元素,在get方法的参数中,写入索引
- size():返回集合的长度,也就是存储元素的个数
- set():设置一个元素
- remove():移除一个元素
Vector 集合
Vector 集合和 ArrayList 集合比较像,他们都是基于数组实现的集合功能,它和 ArrayList 的主要区别在于 Vector 集合中的方法基本都是被 synchronized 关键字修饰的,所以其线程是安全的,但是在性能上低于 ArrayList。
LinkedList 集合
LinkedList 基于链表来实现集合的功能,其实现了静态类节点,集合中的每个对象都由一个节点保存,同时每个节点都拥有到自己的前一个和后一个节点的引用(我们可以想想成指针)。其常用的方法如下:
- addFirst():将指定元素插入此列表的开头
- addLast():将指定元素添加到此列表的结尾
- getFirst():返回此列表的第一个元素
- getLast():返回此列表的最后一个元素
- removeFirst():移除并返回此列表的第一个元素
- removeLast():移除并返回此列表的最后一个元素
ArrayList 和 LinkedList 区别与特点
- 数据结构不同: ArrayList 基于数组来实现;LinkedList 基于链表实现。
- 效率不同: 当随机访问集合(get、set 操作)时,ArrayList 的执行效率比 LinkedList 的执行效率更高,因为 LinkedList 是通过链表来实现的,所以在访问集合时需要移动指针从前往后依次查找;当对数据进行增加和删除的操作(add、remove 操作)时,LinkedList 的执行效率比 ArrayList 的执行效率高,因为 ArrayList 的本质是一个数组,所以在其中进行增删操作后,就需要对操作点之后所有数据的下标进行调整(即进行数据移动),也就导致了在执行增删操作时 ArrayList 的效率更低。我们在选择集合时需要考虑到应用场景的不同,如果多读场景,那么我们就选择 ArrayList 集合,多写的场景则应该选择 LinkedList 集合。
- 线程安全不同: ArrayList 线程安全(效率低),LinkedList 线程不安全(效率高)。
- 空间开销不同: ArrayList 主要空间开销在于需要在 List 列表的结尾预留一定的容量空间;而 LinkList 主要空间开销在于需要存储结点信息以及结点指针信息。
- 自由度不同: ArrayList 自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建集合,然后添加数据,通过调用下标进行使用;而 LinkedList 自由性较高,能够动态的随数据量的变化而变化,但是在使用的时候就不如 ArrayList 方便了。
Map 类的集合
在上面我们已经说到了 Map 接口的基本特点,这里就不多说了,不过我们有一点是需要了解的:Map 将 key 和 value 封装在了一个叫做 Entry 的对象中,Map 中存储的元素实际是 Entry,我们可以在 Map 的源码中验证这一点。

在这里插入图片描述
接下来,我们就直接来看一下 Map 接口的常用实现类
HashMap 集合
HashMap 集合将 Entry 对象存储在了一个数组中,并通过哈希表来实现对 Entry 的快速访问。由每个 Entry 中键(Key值)的哈希值决定该 Entry 在数组中的位置。HashMap 通过这种特性能够实现通过 Key 快速查找到 Entry,从而获得该 Key 对应的 Value 值。在不发生哈希冲突的前提下,查找的时间复杂度是O(1),也正是由于它拥有快速寻值的特点,可以说 HashMap 是最经常被使用的 Map 实现类。其常用的方法如下:
- put (K key, V value):向集合中添加元素(若 Key 值存在则将上次添加的 Value 值替换)
- clear():删除这个集合的所有值
- remove(Object key):根据键(Key)删除集合中的元素
- containsKey(Object key):判断键(Key)是否存在于集合中
如果各位小伙伴想深入了解 HashMap 集合,可移步至大聪明教你学Java | 在 JDK8 中 HashMap 是如何实现的 LinkedHashMap 集合
LinkedHashMap 继承自 HashMap,它的多种操作都是建立在 HashMap 操作的基础上的。与 HashMap 不同的是,LinkedHashMap 维护了一个 Entry 的双向链表,保证了插入的Entry中的顺序(这也是Linked的含义)。虽然LinkedHashMap 增加了时间和空间上的开销,但是它通过维护一个额外的双向链表保证了迭代顺序,可以很方便的解决某些场景下所遇到的问题。
TreeMap 集合
TreeMap 是基于红黑树实现的 Map 结构,其 Entry 类拥有到左/右叶子节点和父节点的引用。红黑树是一种算法复杂但高效的平衡二叉树,具备二叉树的基本性质,即任何节点的值大于其左叶子节点,小于其右叶子节点,利用这种特性,TreeMap 能够实现 Entry 的排序和快速查找。
HashMap、LinkedHashMap、TreeMap的区别与应用场景
HashMap
① HashMap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。遍历时,取得数据的顺序是完全随机的。
② HashMap 最多只允许一条记录的键为Null,允许多条记录的值为 Null。
③HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。
LinkedHashMap
① LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。
② 在遍历的时候会比 HashMap 慢,不过因为 LinkedHashMap 的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关,所以在某些特殊情况下 LinkedHashMap 遍历的效率会高于 HashMap。
TreeMap
① TreeMap实现SortMap接口,能够把它保存的记录根据键排序。它默认的排序方式是按键值的升序排序,当然,我们也可以指定排序的比较器,当我们使用 Iterator 遍历 TreeMap 时,得到的记录也是排序后的记录。
三种集合的应用场景
① 一般情况下,我们用的最多的是HashMap。HashMap 里面存入的键值对在取出的时候是随机的,它根据键的 HashCode 值存储数据,我们也可以根据键可以直接获取它的值,具有很快的访问速度。当我们需要在 Map 中插入、删除和定位元素时,HashMap 是最好的选择。
②LinkedHashMap 是 HashMap 的一个子类,如果需要输出的顺序和输入的相同,那么用 LinkedHashMap 可以实现我们的需求。
③TreeMap 取出来的是排序后的键值对。如果我们需要按自然顺序或自定义顺序遍历键,那么 TreeMap 会更好。 小结
本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨
希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●'◡'●) 如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。
你在被打击时,记起你的珍贵,抵抗恶意; 你在迷茫时,坚信你的珍贵,抛开蜚语; 爱你所爱 行你所行 听从你心 无问东西 |
|