1.list和set的区别
都是继承collection父类,常用的存放数据的集合
list允许重复的元素,set不允许有重复元素
list为有序集合,按照插入时的顺序,set则是无序排列
2.ArraysList和LinkedList的区别
ArraysList:
允许对元素进行快速访问,从中间位置对集合进行插入或删除时,要对数组进行复制,移动,代价很高,所以它适合查找和遍历,并不适合insert和delete(数组实现)
LinkedList:
很适合数据的insert和delete,随机访问数据的速度较慢,还定义了List接口中没定义的方法,专门用于操作表头和表尾的元素,可以当堆栈、队列和双向队列使用(链表实现)
(数组和链表的区别)
3.HashMap和TreeMap的区别
HashMap:
数组形式储存Key Value,线程不安全,k/v允许null值,key不允许元素重复,value允许元素重复。不保证顺序为插入时的顺序,无序排序。hash的key值是先通过hashcode()方法计算出哈希值,接着通过计算得出下标。必须重写应用于key的equals和hashcode方法。
TreeMap:
基于红黑二叉树的NavigableMap实现,线程不安全,k/v不允许null值,key不允许元素重复,value允许元素重复。有序排序,顺序为插入时顺序。迭代输出结果为插入时顺序。
4.HashMap底层原理:
4.1HashMap的put(k,v)方法
1)先将k/v封装进Node对象中
2)通过hash()方法得出key的hash码
3)这时得出map的下标值,通过equals方法拿下标找是否有链表,拿key和链表上的每个节点的k进行比较,如果返回false,那么将value加在链表的最末端,如果返回true,将k对应的节点上的value进行替换。
4.2HashMap的get(k,v)方法
1)先调用k的HashCode()方法得出哈希值,并通过哈希算法转换成数组的下标
2)在数组中通过下标定位到某个位置上。这个位置上什么也没有,就返回null。如果有单向链表,就拿着key和单向链表上每个节点k去进行equals方法,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的k和参数k进行wquals返回true,那么此时该节点的value就是我们要找的value,get方法返回这个value
5.总结
为什么无序:
因为不一定挂在哪个单向链表中,所以加入顺序和取出的不一致
怎么保证不可重复:
使用equals方法来保证key不可重复,如key重复,balue就会覆盖。存放在HashMap集合key部分的元素,其实就是存放在HashSet集合中,则HashSet集合也是要重写hashCode()和equals()
扩容:
HashMap集合的默认初始化容量为16,默认加载因子为0.75,也就是当HashMap集合底层数组的容量达到75%,数组就进行扩容。HashMap集合初始化容量为2的倍数,为了达到散列均匀,提高HashMap集合的存取效率
哈希碰撞:
将多个key通过HashCode()得出的哈希值,输入得到相同的value就是哈希碰撞
扩容的加载因子为什么0.75:
时间成本和空间成本的折中。
时间成本:
如果负载因子是1时,虽然空间利用率提高了,但是带来的哈希碰撞的概率
HashMap中哈希碰撞解决方法用的拉链法,会导致链表越来越长,即使后面会转变为红黑二叉
树,但是因为查询效率很低,所以会导致时间成本上升
空间成本:
如果负载因子太低,会导致空间占用率太低,比如大小为64,32都未被使用。
所以为了双向平衡将负载因子设置为0.75
链表转红黑树的阈值为什么是8:
负载因子为0.75时,可以计算出哈希碰撞的概率
碰撞8次概率非常小基本不可能
所以将阈值设置为8,避免链表转红黑树这样耗性能行为发生
JDK1.8之后改动:
当单向链表的元素超过8个,将链表转为红黑树结构。如果红黑树元素低于6,红黑树转为单向链表