Java的集合类被定义在Java.util包中,主要有4种集合,分别为List、Queue、Set和Map,每种集合的具体分类如图所示。
1. List:可重复
List是很常用的数据类型,是有序的集合,一共有三个实现类,分别是ArrayList、Vector和LinkedList。
1.ArrayList:数组实现,增删慢,查询快,线程不安全
ArrayList是使用最广泛的List实现类,其内部数据结构基于数组实现,提供了对List的增加(add)、删除(remove)和访问(get)功能。
ArrayList的缺点是元素必须连续存储,当需要在ArrayList的中间位置插入或者删除元素时,需要将待插入或者删除的节点后的所有元素进行移动,其修改代价较高,因此,ArrayList不适合随机插入和删除的操作,更适合随机查找和遍历的操作。
ArrayList 不需要在定义时指定数组的长度,在数组长度不能满足存储要求时,ArrayList会创建一个新的更大的数组并将数组中已有的数据复制到新的数组中。
2.Vector:数组实现,增删慢,查询快,线程安全
Vector的数据结构和ArrayList一样,都是基于数组实现的,不同的是Vector支持线程同步,即同一时刻只允许一个线程对Vector进行写操作(新增、删除、修改),以保证多线程环境下数据的一致性,但需要频繁地对Vector实例进行加锁和释放锁操作,因此,Vector的读写效率在整体上比ArrayList低。
3.LinkedList:双向链表实现,增删快,查询慢,线程不安全
LinkedList采用双向链表结构存储元素,在对LinkedList进行插入和删除操作时,只需在对应的节点上插入或删除元素,并将上一个节点元素的下一个节点的指针指向该节点即可,数据改动较小,因此随机插入和删除的效率很高。但在对LinkedList进行随机访问时,需要从链表的头部一直遍历到该节点为止,因此随机访问速度很慢。LinkedList还提供了在List接口中未定义的方法,用于操作链表头部和尾部的元素,因此有时可被当作堆栈和队列使用。
相关面试题
(1)ArrayList和LinkedList有什么区别?★★★☆☆
(2)对List集合去重都有哪些方法?★★★☆☆
(3)数组和链表分别适用于什么场景,为什么?★★★☆☆
(4)ArrayList和LinkedList的底层数据结构是什么?★★★☆☆
2. Queue
Queue是队列结构,Java中的常用队列如下。
◎ ArrayBlockingQueue:基于数组数据结构实现的有界阻塞队列。
◎ LinkedBlockingQueue:基于链表数据结构实现的有界阻塞队列。
◎ PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
◎ DelayQueue:支持延迟操作的无界阻塞队列。
◎ SynchronousQueue:用于线程同步的阻塞队列。
◎ LinkedTransferQueue:基于链表数据结构实现的无界阻塞队列。
◎ LinkedBlockingDeque:基于链表数据结构实现的双向阻塞队列。
相关面试题
(1)你在开发中用过哪些队列,分别是在哪些场景下使用的?★☆☆☆☆
3. Set:不可重复
Set 的核心特性是独一无二,适用于存储无序且值不相等的元素。对象的相等性在本质上是对象的HashCode值相同,Java依据对象的内存地址计算出对象的HashCode值。如果想要比较两个对象是否相等,则必须同时覆盖对象的hashCode方法和equals方法,并且hashCode方法和equals方法的返回值必须相同。
1.HashSet:HashMap实现,无序
HashSet 存放的是哈希值,它是按照元素的哈希值来存取元素的。元素的哈希值是通过元素的hashCode方法计算得到的,HashSet首先判断两个元素的哈希值是否相等,如果哈希值相等,则接着通过equals方法比较,如果equals方法返回的结果也为true,HashSet就将其视为同一个元素;如果equals方法返回的结果为false,HashSet就将其视为不同的元素。
2.TreeSet:二叉树实现
TreeSet基于二叉树对新添加的对象按照指定的顺序排序(升序、降序),每添加一个对象都会进行排序,并将对象插入二叉树指定的位置。
Integer和String等基础对象类型可以直接根据TreeSet的默认排序进行存储,而自定义的数据类型必须实现Comparable接口,并且覆写其中的compareTo函数才可以按照预定义的顺序存储。如果覆写compareTo函数,则在升序时在this.对象小于指定对象的条件下返回-1,在降序时在this.对象大于指定对象的条件下返回1。
3.LinkHashSet:继承HashSet,通过HashMap实现数据存储,双向链表记录顺序
LinkedHashSet在底层使用LinkedHashMap存储元素,它继承了HashSet,所有的方法和操作都与HashSet相同,因此LinkedHashSet的实现比较简单,只提供了4个构造方法,并通过传递一个标识参数调用父类的构造器,在底层构造一个LinkedHashMap来记录数据访问,其他相关操作与父类HashSet相同,直接调用父类HashSet的方法即可。
相关面试题
(1)Set如何保证元素不重复?★★★☆☆
(2)HashSet的原理是什么?★★☆☆☆
(3)TreeSet在排序时是如何比较元素的?★★☆☆☆
4. Map
1.HashMap:数组+链表存储数据,线程不安全
HashMap基于键的HashCode值唯一标识一条数据,同时基于键的HashCode值进行数据的存取,因此可以快速地更新和查询数据,但其每次遍历的顺序无法保证相同。HashMap的key和value允许为null。
HashMap是非线程安全的,即在同一时刻有多个线程同时写HashMap时将可能导致数据的不一致。如果需要满足线程安全的条件,则可以用Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。
Java 8中HashMap的数据结构如下图所示,其中,HashMap的数据结构为数组+链表或红黑树。数组中的每个Entry实例(元素)都是一个链表或红黑树,默认数组中的Entry实例数据结构为链表,当链表中的元素个数超过8个以后,HashMap会将链表结构转换为红黑树结构以提高查询效率。
HashMap在查找数据时,首先根据HashMap的哈希值快速定位到数组的具体下标,但是在找到数组下标后,如果数组中的Entry实例为链表,则需要对链表进行顺序遍历直到找到需要的数据,其时间复杂度为O(n)。但是如果数组中的Entry实例的数据结构为红黑树,则其进行数据查找的时间复杂度为O ,因此在效率上有很大的提升。
HashMap常用的参数如下。
◎ capacity:当前数组的容量,默认为16,可以扩容,扩容后数组的大小为当前的两倍,因此该值始终为 。
◎ loadFactor:负载因子,默认为0.75。
2.ConcurrentHashMap
ConcurrentHashMap在JDK 1.7和JDK 1.8中的实现方式不同。
JDK 1.7 ConcurrentHashMap的实现回顾:JDK 1.7及之前版本的ConcurrentHashMap采用分段锁的思想实现并发操作,因此是线程安全的。ConcurrentHashMap由多个Segment组成(Segment的数量也是锁的并发度),每个Segment均继承自ReentrantLock并单独加锁,所以每次进行加锁操作时锁住的都是一个Segment,这样只要保证每个Segment都是线程安全的,也就实现了全局的线程安全。具体的数据结构如图2-4所示。在ConcurrentHashMap中,concurrencyLevel参数表示并行级别,默认是16,也就是说ConcurrentHashMap默认由16个Segments组成,在这种情况下最多同时支持16个线程并发执行写操作,只要它们的操作分布在不同的Segment上即可。并行级别concurrencyLevel可以在初始化时设置,一旦初始化就不可更改。ConcurrentHashMap的每个Segment内部的数据结构都和HashMap相同。
JDK 1.8 ConcurrentHashMap的实现:在JDK 1.8以后的版本中,ConcurrentHashMap弃用了Segment分段锁,改用Synchronized+CAS实现对多线程的安全操作。同时,JDK 1.8在ConcurrentHashMap中引入了红黑树,具体的数据结构如下图所示。
3.HashTable:线程安全
HashTable是遗留类,很多映射的常用功能都与HashMap类似,不同的是它继承自Dictionary类,并且是线程安全的,同一时刻只有一个线程能写HashTable,并发性不如ConcurrentHashMap。
4.TreeMap:基于二叉树数据结构
TreeMap基于二叉树数据结构存储数据,同时实现了SortedMap接口以保障元素的顺序存取,默认按键值的升序排序,也可以自定义排序比较器。
TreeMap常用于实现排序的映射列表。在使用TreeMap时,其key必须实现Comparable接口或采用自定义的比较器,否则会抛出java.lang.ClassCastException异常。
5.LinkedHashMap:继承HashMap,使用链表保存插入顺序
LinkedHashMap为HashMap的子类,其内部使用链表保存元素的插入顺序,当通过Iterator遍历LinkedHashMap时,会按照元素的插入顺序访问元素。
很高兴为大家推荐我的新书《Offer来了.第二版》。本书在第一版的基础上结合读者的反馈做了大量的调整,那么他的主要特点有哪些呢?。
1.“全”:他囊括了Java核心知识点以及周边全生态,包括,Java基础和高级应用,常用大数据组件原理和实战,Java高并发编程,数据结构和算法,设计模式等等。可以说是全网知识点最全的一本Java书籍。
2.“新”:本书结合最新技术发展添加了,Java流计算,Spring Cloud Alibaba 等最新内容。
3.“简洁”:本书架构简洁,深入浅出,图文结合,力求以最简洁的语言描述清楚每个知识点。
4.“贴心”,本书还在每小节放置了个大厂面试题,总共300多个大厂面题,方便读者在读完每部分内容后及时实战。
同时作为面试官的你是不是也感觉面试过程越来越卷了,自己的知识储备不够了呢?别慌,本书为你总结了最全的面试知识点和面试题库,面试官再也不用为没有题库而发愁了。
总的来说本书即是Java面霸手册,也是面试官的参考题库,同时也是每个Java程序员的必备按头书。
“一书在手,Offer我有”,小伙伴们赶快预定起来吧!