深入理解Java基础中的集合框架

 更新时间:2023年08月26日 14:46:30   投稿:yin  
Java集合框架(Java Collections Framework, JCF)也称容器,这里可以类比 C++中的 STL,在这里主要对如下部分进行源码分析,及在面试中常见的问题,例如,在阿里面试常问到的 HashMap和ConcurrentHashMap原理等等,深入源码分析是面试中必备的技能

Java集合框架 (Java Collections Framework, JCF) 也称容器,这里可以类比 C++ 中的 STL,在市面上似乎还没能找到一本详细介绍的书籍。在这里主要对如下部分进行源码分析,及在面试中常见的问题。

例如,在阿里面试常问到的 HashMap 和 ConcurrentHashMap 原理等等。深入源码分析是面试中必备的技能,通过本文的阅读会对集合框架有更深一步的了解。

一、概述

Java集合框架提供了数据持有对象的方式,提供了对数据集合的操作。Java 集合框架位于java.util包下,主要有三个大类:Collection(接口)Map(接口)集合工具类

Collection

  • ArrayList线程不同步。默认初始容量为 10,当数组大小不足时容量扩大为 1.5 倍。为追求效率,ArrayList 没有实现同步(synchronized),如果需要多个线程并发访问,用户可以手动同步,也可使用 Vector 替代。
  • LinkedList线程不同步双向链接实现。LinkedList 同时实现了 List 接口和 Deque 接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack)。这样看来,LinkedList 简直就是个全能冠军。当你需要使用栈或者队列时,可以考虑使用 LinkedList,一方面是因为 Java 官方已经声明不建议使用 Stack 类,更遗憾的是,Java 里根本没有一个叫做 Queue 的类(它是个接口名字)。关于栈或队列,现在的首选是 ArrayDeque,它有着比 LinkedList(当作栈或队列使用时)有着更好的性能。
  • Stack and Queue:Java 里有一个叫做 Stack 的类,却没有叫做 Queue 的类(它是个接口名字)。当需要使用栈时,Java 已不推荐使用 Stack,而是推荐使用更高效的 ArrayDeque;既然 Queue 只是一个接口,当需要使用队列时也就首选 ArrayDeque 了(次选是 LinkedList )。
  • Vector线程同步。默认初始容量为 10,当数组大小不足时容量扩大为 2 倍。它的同步是通过Iterator方法加synchronized实现的。
  • Stack线程同步。继承自 Vector,添加了几个方法来完成栈的功能。现在已经不推荐使用 Stack,在栈和队列中有限使用 ArrayDeque,其次是 LinkedList。
  • TreeSet线程不同步,内部使用NavigableMap操作。默认元素 “自然顺序” 排列,可以通过Comparator改变排序。TreeSet 里面有一个 TreeMap(适配器模式)
  • HashSet线程不同步,内部使用 HashMap 进行数据存储,提供的方法基本都是调用 HashMap 的方法,所以两者本质是一样的。集合元素可以为 NULL。
  • Set:Set 是一种不包含重复元素的 Collection,Set 最多只有一个 null 元素。Set 集合通常可以通过 Map 集合通过适配器模式得到。
  • PriorityQueue:Java 中 PriorityQueue 实现了 Queue 接口,不允许放入 null 元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为 PriorityQueue 的底层实现。
    • 优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java 的优先队列每次取最小元素,C++ 的优先队列每次取最大元素)。这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator,类似于 C++ 的仿函数)。
  • NavigableSet:添加了搜索功能,可以对给定元素进行搜索:小于、小于等于、大于、大于等于,放回一个符合条件的最接近给定元素的 key。
  • EnumSet:线程不同步。内部使用 Enum 数组实现,速度比HashSet快。只能存储在构造函数传入的枚举类的枚举值

Map

  • TreeMap:线程不同步,基于红黑树(Red-Black tree)的 NavigableMap 实现,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用 Iterator 遍历 TreeMap 时,得到的记录是排过序的。
    • TreeMap 底层通过红黑树(Red-Black tree)实现,也就意味着containsKey(),get(),put(),remove()都有着log(n)的时间复杂度。其具体算法实现参照了《算法导论》。
  • HashTable线程安全,HashMap 的迭代器 (Iterator) 是fail-fast迭代器。HashTable 不能存储 NULL 的 key 和 value。
  • HashMap:线程不同步。根据keyhashcode进行存储,内部使用静态内部类Node的数组进行存储,默认初始大小为 16,每次扩大一倍。当发生 Hash 冲突时,采用拉链法(链表)。JDK 1.8中:当单个桶中元素个数大于等于8时,链表实现改为红黑树实现;当元素个数小于6时,变回链表实现。由此来防止hashCode攻击。
    • Java HashMap 采用的是冲突链表方式。
    • HashMap 是 Hashtable 的轻量级实现,可以接受为 null 的键值 (key) 和值 (value),而 Hashtable 不允许。
  • LinkedHashMap保存了记录的插入顺序,在用 Iterator 遍历 LinkedHashMap 时,先得到的记录肯定是先插入的。也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比 HashMap 慢,不过有种情况例外,当 HashMap 容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap 慢,因为 LinkedHashMap 的遍历速度只和实际数据有关,和容量无关,而 HashMap 的遍历速度和他的容量有关。
  • WeakHashMap:从名字可以看出它是某种 Map。它的特殊之处在于 WeakHashMap 里的 entry 可能会被 GC 自动删除,即使程序员没有调用remove()或者clear()方法。 WeakHashMap 的存储结构类似于HashMap
    • 既然有 WeekHashMap,是否有 WeekHashSet 呢?答案是没有!不过 Java Collections 工具类给出了解决方案,Collections.newSetFromMap(Map<E,Boolean> map)方法可以将任何 Map包装成一个Set。

集合工具类

  • CollectionsArrays:集合类的一个工具类帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

  • ComparableComparator:一般是用于对象的比较来实现排序,两者略有区别。

    • 类设计者没有考虑到比较问题而没有实现 Comparable 接口。这是我们就可以通过使用 Comparator,这种情况下,我们是不需要改变对象的。
    • 一个集合中,我们可能需要有多重的排序标准,这时候如果使用 Comparable 就有些捉襟见肘了,可以自己继承 Comparator 提供多种标准的比较器进行排序。

说明:线程不同步的时候可以通过,Collections.synchronizedList() 方法来包装一个线程同步方法

通用实现

Implementations
Hash TableResizable ArrayBalanced TreeLinked ListHash Table + Linked List
InterfacesSetHashSetTreeSetLinkedHashSet
ListArrayListLinkedList
DequeArrayDequeLinkedList
MapHashMapTreeMapLinkedHashMap

到此这篇关于深入理解Java基础中的集合框架的文章就介绍到这了,更多相关Java集合框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 三道MySQL新手入门面试题,通往自由的道路

    三道MySQL新手入门面试题,通往自由的道路

    这篇文章主要为大家分享了最有价值的3道MySQL面试题,,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • Spring实现文件上传的配置详解

    Spring实现文件上传的配置详解

    这篇文章将为大家详细说明一下spring上传文件如何配置,以及从request请求中解析到文件流的原理,文中示例代码讲解详细,感兴趣的可以了解一下
    2022-08-08
  • java开发微信公众号支付

    java开发微信公众号支付

    这篇文章主要给大家结合微信支付接口开发的实践,从获取用户授权到各主要接口的使用方法等方面介绍微信支付的关键点技术,有需要的小伙伴可以参考下
    2015-08-08
  • JAVA实现Base64编码的三种方式

    JAVA实现Base64编码的三种方式

    本文主要介绍了JAVA实现Base64编码的三种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • 详解java模板和回调机制

    详解java模板和回调机制

    这篇文章主要为大家详细介绍了java模板和回调机制,学习java模板,感兴趣的朋友可以参考一下
    2016-03-03
  • 微服务Springcloud之Feign的基本使用

    微服务Springcloud之Feign的基本使用

    这篇文章主要介绍了微服务Springcloud之Feign的基本使用,Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解,需要的朋友可以参考下
    2023-03-03
  • Java毕业设计实战项目之宠物商城系统的实现流程

    Java毕业设计实战项目之宠物商城系统的实现流程

    这是一个使用了java+Springboot+Maven+mybatis+Vue+mysql开发的宠物商城系统,是一个毕业设计的实战练习,具有宠物商城该有的所有功能,感兴趣的朋友快来看看吧
    2022-01-01
  • Java如何获取Object中Value

    Java如何获取Object中Value

    在Java中,获取Object中的值需依赖于对象的类型和属性,常用方法包括使用反射、getter方法、接口或抽象类、Map等数据结构,本文给大家介绍Java如何获取Object中Value,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • 在Spring MVC中处理请求参数的方法总结

    在Spring MVC中处理请求参数的方法总结

    在Spring MVC中处理请求参数是通过使用各种注解来实现的,本文给大家介绍了在Spring MVC中处理不同类型请求参数的方法,并通过代码讲解的非常详细,需要的朋友可以参考下
    2024-08-08
  • Spring注解开发@Bean和@ComponentScan使用案例

    Spring注解开发@Bean和@ComponentScan使用案例

    这篇文章主要介绍了Spring注解开发@Bean和@ComponentScan使用案例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09

最新评论