深入理解Java集合框架:List、Set、Map的原理与特性详解
大家应该都熟悉集合系统,尤其是我们经常使用的List和Map的原理。这里我们可以看一下这张图:

1.List、Set、Map都是继承自Collection接口吗?
List 和 Set 是,Map 不是。 Map是一个键值对映射容器,它与List和Set有明显的不同。集合存储的是分散的元素,不允许有重复的元素(数学中的集合也是如此)。 List是一个线性结构的容器,适合存放数值。对元素的索引访问。
2、讲解ArrayList、Vector、LinkedList的存储性能及特点。
ArrayList和Vector都使用数组来存储数据。数组元素的数量大于实际存储的数据,以便可以添加和插入元素。它们都允许直接通过序号对元素进行索引,但是插入元素涉及到移动数组元素等内存操作,因此索引数据快但插入数据慢。因为Vector中的方法是用synchronized修饰的,所以Vector是一个线程安全的容器,但性能比ArrayList差,所以它已经是Java中的遗留容器了。
LinkedList使用双向链表来实现存储(通过额外的引用将内存中分散的内存单元关联起来,形成可以按序号索引的线性结构。与数组的连续存储方式相比,这种链接存储方式具有更好的内存性利用率较高),按序号索引数据需要向前或向后遍历,但插入数据时只需要记录本项前后的项,因此插入速度较快。
Vector是遗留容器(Java早期版本提供的容器,另外Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器),不再推荐使用。但是,由于 ArrayList 和 LinkedListed 都不是线程安全的。如果遇到多线程操作同一个容器的场景,可以在使用之前通过工具类Collections中的synchronizedList方法将其转为线程安全的容器(这是装饰模式的一种应用,已经会用了) )。一个对象被传递到另一个类的构造函数中以创建一个新对象以增强实现)。
3. 收藏和收藏有什么区别?
Collection是一个接口,是Set、List等容器的父接口; Collections是一个工具类,提供了一系列静态方法来辅助容器操作。这些方法包括容器搜索、排序、线程安全等。
4、List、Map、Set这三个接口在访问元素时各有什么特点?
列表使用特定索引访问元素,并且可以包含重复元素。
Set不能存储重复的元素(使用对象的equals()方法来区分元素是否重复)。
Map保存的是键值对映射,映射关系可以是一对一或多对一的。
Set和Map容器都有基于哈希存储和排序树的两个实现版本。基于哈希存储的版本理论访问时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时时间复杂度较长。根据元素或元素的键形成排序树,以达到排序和去重的效果。
5.List和Set的区别
集合是最简单的集合。集合中的对象不以特定方式排序,并且不存在重复的对象。
List的特点是其元素以线性方式存储,集合中可以存储重复的对象。
6.LinkedHashMap和PriorityQueue的区别
PriorityQueue 是一个优先级队列,它确保最高或最低优先级的元素始终位于队列的头部,但 LinkedHashMap 维护的顺序是元素插入的顺序。遍历 PriorityQueue 时,没有顺序保证,但 LinkedHashMap 类保证遍历顺序是元素插入的顺序。
7、WeakHashMap和HashMap有什么区别?
WeakHashMap 的工作方式与普通 HashMap 类似,但使用弱引用作为键,这意味着当键对象没有任何引用时,键/值将被回收。
8.ArrayList和LinkedList有什么区别?
最明显的区别是,ArrayList的底层数据结构是数组,支持随机访问,而LinkedList的底层数据结构是双向循环链表,不支持随机访问。使用下标访问元素,ArrayList的时间复杂度为O(1),而LinkedList的时间复杂度为O(n)。
与ArrayList相比,LinkedList的插入、添加和删除操作更快,因为当向集合中的任意位置添加元素时,不需要像数组那样重新计算大小或更新索引。
LinkedList比ArrayList占用更多内存,因为LinkedList为每个节点存储两个引用,一个指向前一个元素,一个指向下一个元素。
9.ArrayList和Array有什么区别?
Array可以保存基本类型和对象,而ArrayList只能保存对象。
Array有指定的大小,而ArrayList有固定的大小
10.ArrayList和Vector的区别
ArrayList 和 Vector 在很多方面都非常相似。
下面是ArrayList和Vector的区别。
11.HashMap和Hashtable的区别
HashMap和Hashtable都实现了Map接口,因此很多功能非常相似。但是,它们有以下区别:
12.HashSet和HashMap的区别 13.HashMap和ConcurrentHashMap的区别
引入ConcurrentHashMap是为了在同步集合HashTable之间有更好的选择。 HashTable、HashMap 和 ConcurrentHashMap 的主要区别在于 HashMap 不是同步的、线程不安全的、不适合在多线程并发环境中使用,而 ConcurrentHashMap 是线程安全的。集合容器,特别是在多线程和并发环境下,经常被用作Map的主要实现。
14. 比较器和比较器有什么区别?
Comparable 接口用于定义对象的自然顺序,而比较器通常用于定义用户自定义的顺序。始终只有一个 Comparable,但可以有多个比较器来定义对象的顺序。
15. poll()方法和remove()方法有什么区别?
poll()和remove()都是从队列中取出一个元素,但是poll()在获取元素失败时会返回null,但是remove()在失败时会抛出异常。
16、ArrayList、HashMa、LinkedList的默认空间是多少?扩容机制是什么?
代码语言:javascript
复制
private static final int DEFAULT_CAPACITY = 10;
//from HashMap.java JDK 7
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
17.如何实现集合排序?
您可以使用有序集合,例如 TreeSet 或 TreeMap,也可以使用有序集合(例如列表),然后使用 Collections.sort() 对其进行排序。
18. 如何打印数组的内容
您可以使用 Arrays.toString() 和 Arrays.deepToString() 方法来打印数组。因为数组没有实现 toString() 方法,所以如果将数组传递给 System.out.println() 方法,将无法打印出数组的内容,但 Arrays.toString() 可以打印每个元素。
19、LinkedList是单向链表还是双向链表?
双向循环链表,具体实现可以自行查看源码。
20.TreeMap的实现原理
它是使用红黑树实现的,具体实现可以自行查看源码。
21. 遍历ArrayList时如何正确移除一个元素
这个问题的关键在于面试官是使用ArrayList的remove()方法还是Iterator的remove()方法。下面是一个示例代码,它在遍历过程中使用正确的方法删除元素,并且不会出现 ConcurrentModificationException 异常。
22.什么是ArrayMap?它和HashMap有什么区别呢?
ArrayMap 在 Android SDK 中提供,非 Android 开发者可以跳过它。
ArrayMap使用两个数组来模拟map,占用内存更少,效率更高。
详细请参考这篇文章:ArrayMap VS HashMap: %5D
23、如何决定使用HashMap还是TreeMap?
对于Map中元素的插入、删除、定位等操作,HashMap是最佳选择。但是,如果您需要迭代键的有序集合,TreeMap 是更好的选择。根据集合的大小,将元素添加到 HashMap 并用 TreeMap 替换映射以进行有序键遍历可能会更快。
24、HashMap的实现原理 HashMap概述:HashMap是基于哈希表的Map接口的异步实现。该实现提供了所有可选的映射操作并允许空值和空键。此类不保证映射的顺序,特别是它不保证顺序是不可变的。 HashMap数据结构:在Java编程语言中,有两种最基本的结构,一种是数组,另一种是模拟指针(引用)。所有的数据结构都可以利用这两种基本结构来构造,HashMap也不例外。 HashMap实际上是一种“链表哈希”数据结构,它是数组和链表的组合。
当我们往Hashmap中放入一个元素时,首先根据key的hashcode重新计算hash值,并根据hash值得到该元素在数组中的位置(下标)。如果数组在该位置已经存储了其他元素,那么在该位置的元素会以链表的形式存储,新添加的放在链头,最先添加的元素放在链表的后面。链的末端。如果数组中该位置没有元素,则直接将该元素放到数组中该位置。
需要注意的是,HashMap的实现在Jdk 1.8中已经进行了优化。当链表中的节点数据超过8个时,链表将转为红黑树以提高查询效率,从原来的O(n)变为O(logn)
25.ConcurrentHashMap工作原理及代码实现
ConcurrentHashMap是如何实现线程安全的呢?当然不可能给每个方法都加上synchronized,这样就变成了HashTable。
从ConcurrentHashMap代码可以看出,它引入了“段锁”的概念,可以理解为将一个大Map拆分成N个小HashTable,根据key.hashCode()决定key放在哪个HashTable中。
在ConcurrentHashMap中,Map被分为N个Segments。 put和get时,根据key.hashCode()计算段。
26. Fail-fast 和 Fail-safe 之间有什么区别?
Iterator的fail-fast属性适用于当前集合,因此它不会受到集合中任何更改的影响。 Java.util 包中的所有集合类都被设计为失败->快速,而 java.util.concurrent 中的集合类都是故障安全的。当快速失败迭代器检测到正在迭代的集合的结构已更改时,它会抛出 ConcurrentModificationException,而故障安全迭代器永远不会抛出 ConcurrentModificationException。
27. 告诉我一些在 Java 中使用集合的最佳实践。
以下是我在 Java 中使用 Collectionc 类的一些最佳实践:
28.什么是BlockingQueue?
Java.util.concurrent.BlockingQueue 是一个队列。当检索或删除元素时,它会等待队列变为非空;添加元素时,它会等待队列中的可用空间。 BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用空间,或者消费者有可用对象,因为这一切都在 BlockingQueue 实现类中处理。 Java提供了集中式BlockingQueue的实现,例如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue和SynchronousQueue
29.什么是队列和栈?列出他们的区别?
栈和队列都是用来预存数据的。 java.util.Queue是一个接口,其实现类位于Java并发包中。队列允许以先进先出 (FIFO) 的方式检索元素,但情况并非总是如此。 Deque 接口允许从两端检索元素。
堆栈与队列类似,但它允许后进先出 (LIFO) 检索元素。
Stack是一个从Vector扩展的类,而Queue是一个接口。
原来的: