- Collection的体系结构,Java容器有哪些?
List:
ArrayList
Vector
LinkedList
Set:
HashSet
TreeSet
Queue:
PriorityQueue
ArrayQueue
Map:
HashMap
LinkedHashMap
Hashtable
TreeMap - HashMap底层数据结构jdk1.7和1.8的区别
HashMap 主要用来存放键值对,它基于哈希表的 Map 接口实现,是常用的 Java 集合之一,是非线程安全的
JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的 hashcode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突
JDK1.8 之后
相比于之前的版本, JDK1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间 - 解决 hash 碰撞的方法
为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的,先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标 - HashMap 有哪几种常见的遍历方式?
HashMap 遍历从大的方向来说,可分为以下 4 类:
迭代器(Iterator)方式遍历;
For Each 方式遍历;
Lambda 表达式遍历(JDK 1.8+);
Streams API 遍历(JDK 1.8+) - ConcurrentHashMap的实现,底层原理。
ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成
jdk1.7和1.8的区别
线程安全实现方式 :JDK 1.7 采用 Segment 分段锁来保证安全, Segment 是继承自 ReentrantLock。JDK1.8 放弃了 Segment 分段锁的设计,采用 Node + CAS + synchronized 保证线程安全,锁粒度更细,synchronized 只锁定当前链表或红黑二叉树的首节点。
Hash 碰撞解决方法 : JDK 1.7 采用拉链法,JDK1.8 采用拉链法结合红黑树(链表长度超过一定阈值时,将链表转换为红黑树)。
并发度 :JDK 1.7 最大并发度是 Segment 的个数,默认是 16。JDK 1.8 最大并发度是 Node 数组的大小,并发度更大 - HashTable、HashMap、HashSet区别。
线程是否安全: HashMap 是非线程安全的,Hashtable 是线程安全的
效率: 因为线程安全的问题,HashMap 要比 Hashtable 效率高一点
初始容量大小和每次扩充容量大小的不同 :创建时如果不指定容量初始值,Hashtable 默认的初始大小为 11,之后每次扩充,容量变为原来的 2n+1。HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍
底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化
HashSet底层就是基于HashMap实现的 - ArrayList,LinkedList ,Vector的区别?
ArrayList 是 List 的主要实现类,底层使用 Object[]存储,适用于频繁的查找工作,线程不安全 ;
Vector 是 List 的古老实现类,底层使用Object[] 存储,线程安全的
我们在项目中一般是不会使用到 LinkedList 的,需要用到 LinkedList 的场景几乎都可以使用 ArrayList 来代替,并且,性能通常会更好 - ArrayList 的扩容机制
ArrayList 的底层是数组队列,相当于动态数组
以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10