Collection 接口下的有:
List:
- ArrayList
- LinkedList
- Vector
Set:
- HashSet
- TreeSet
- LinkedHashSet
Queue:
- LinkedList
- PriorityQueue
Map 接口下的有:
- HashMap
- ArrayList
- LinkedList
- Vector
Set:
- HashSet
- TreeSet
- LinkedHashSet
Queue:
- LinkedList
- PriorityQueue
Map 接口下的有:
- HashMap
- LinkedList
- PriorityQueue
Map 接口下的有:
- HashMap
HashMap 主要用来存放键值对,可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个。它不保证元素顺序,并且是非线程安全的。
- TreeMap
- LinkedHashMap
这几个就够啦,剩下的要么不常用,要么就是淘汰的集合,面试你不提 基本没人问。
要想加深认识,就得去JavaGuide 、全栈知识,多深入学习
ArrayList和LinkedList的区别
- 底层数据结构:ArrayList 底层使用的是 Object 数组elementData。LinkedList 底层使用的是双向链表。(JDK1.6 之前为循环链表,JDK1.7 取消了循环)
- 是否支持快速随机访问:ArrayList 支持高效的随机元素访问,通过元素的序号快速获取元素对象( get(int index) ),LinkedList 不支持。
- 内存空间占用:ArrayList 的空间占用主要体现在在 list 的结尾会预留一定的容量空间。LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放两个引用以及数据)
- 插入数据的效率:
- 在尾部插入数据,数据量较小时LinkedList比较快,因为ArrayList要频繁扩容,当数据量大时ArrayList比较快,因为ArrayList扩容是当前容量*1.5,大容量扩容一次就能提供很多空间,当ArrayList不需扩容时效率明显比LinkedList高,因为是直接对数组元素赋值而不需new Node
- 在首部插入数据,LinkedList较快,因为LinkedList遍历插入位置花费时间很小,而ArrayList需要将原数组所有元素进行一次 arraycopy
- 插入位置越往中间,LinkedList效率越低,因为它遍历获取插入位置是从两头往中间搜,index越往中间遍历越久,因此ArrayList的插入效率可能会比LinkedList高
- 插入位置越往后,ArrayList效率越高,因为数组需要复制后移的数据少了,那么 arraycopy 就快了,因此在首部插入数据LinkedList效率比ArrayList高,尾部插入数据ArrayList效率比LinkedList高
HashMap的实现原理 / 底层数据结构?
JDK1.8 之前,HashMap 底层是 数组和链表 实现的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。采用拉链法解决冲突。
JDK1.8 以后,HashMap 底层是由 数组+链表+红黑树 组成的。以前在查找的时候,首先根据 hash 值快速定位到数组的具体下标,之后需要顺着链表一个个找下去,时间复杂度取决于链表的长度,为 O(n)。为了降低这部分的开销,JDK1.8中,当链表长度大于默认为 8 的阈值时,会判断当前数组长度是否小于 64,如果小于则先进行数组扩容,否则将链表转化为红黑树,来减少搜索时间。
解决hash冲突的方法?
- 开放地址法:一旦发生了冲突,就去寻找下一个空的散列地址。
- 再哈希法:对于冲突的哈希值再次进行哈希处理,直到没有哈希冲突。
- 拉链法:对于相同的值,使用链表进行连接。这个就是HashMap使用的方法。
- 建立公共溢出区:建立公共溢出区存储所有哈希冲突的数据。
用过concurrenthashmap吗,讲一下?
JDK1.7底层实现:
JDK1.7底层实现:
Java使用了分段锁机制实现ConcurrentHashMap。
ConcurrentHashMap的数据结构是由一个Segment 数组和多个HashEntry组成,Segment 数组的意义就是将一个大的Hash表分割成多个段,而每一个Segment 元素存储的是 HashEntry数组+链表,类似HashMap。
Segment 通过继承 ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment元素,这样只要保证每个 segment 是线程安全的,也就实现了全局的线程安全。
并发环境下,对于同一个 segment 的操作才需考虑线程同步,不同的 segment 不需要考虑。
默认 Segment 数组长度为 16,并且一旦初始化就不能改变。
也可以认为 ConcurrentHashMap 默认支持最多16个线程并发。
JDK1.8底层实现:
在JDK1.7之前,ConcurrentHashMap 最大并发度受Segment的个数限制。
因此,在JDK1.8中,ConcurrentHashMap的实现原理 选择了与HashMap类似的数组+链表+红黑树的方式实现,而加锁则采用CAS和synchronized实现。
一个list拼接另一个list用什么方法?
addAll() 方法: addAll(int index, Collection c)
其中 index 是可选参数,用来指定插入的位置。默认是添加到末尾。
HashMap怎么遍历key? 创建HashMap对象Map1.EntrySet 遍历:map = new HashMap<>();
for (Map.Entry2.KeySet 遍历:entry : map.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); }
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
3.EntrySet 迭代器遍历:
Iterator4.KeySet 迭代器遍历:> entryIterator = map.entrySet().iterator(); while (entryIterator.hasNext()) { Map.Entry entry = entryIterator.next(); System.out.println(entry.getKey() + ":" + entry.getValue()); }
IteratorkeySetIterator = map.keySet().iterator(); while (keySetIterator.hasNext()) { String key = keySetIterator.next(); System.out.println(key + ":" + map.get(key)); }



