关于Java集合的部分复习知识点整理

关于Java集合的部分复习知识点整理

ArrayList

  1. ArrayList本质上继承了AbstractList,而AbstractList则是继承了Collection集合类,并且Arraylist是实现了List的接口
  2. ArrayList初始的容量,DEFAULT_CAPACITY = 10,即初始容量为10,但初始化对象的时候可以传入你自定义的容量最大容量为Interger.MaxValue-8
  3. ArrayList的默认元素存储,是一个Object[]数组
  4. ArrayList源码里面存在一个ensureCapacity的方法,用来确认数组的容量是否需要扩容,扩容的时候采用的是Arrays.Copyof的方法,复制元素到一个新的数组
  5. 关于ArrayList的扩容机制,达到了定义容量(不传入容量的话,即为默认容量)的时候,会动态扩容1.5倍,也是采用上述的复制方法
  6. ArrayList其实是存在手动缩容的方法的,在源码中有叫做 trimToSize()的方法,一般是手动调用的
  7. ArrayList中删除元素的Remove方法其实也是采用arraycopy()的方法来进行元素的移动,本质跟数组差不多
  8. ArrayList是线程不安全的,里面没有实现线程安全的保障,多线程在访问的时候,实现的自动扩容也是造成线程不安全的一部分原因。相反,常见的Vector基本上是靠synchronized来实现线程安全的

HashMap

  • HashMap实现了Map接口,初始容量为16,最大容量为1 << 30,默认加载因子为0.75,如果自己传入初始值K,则容量为大于K的2次方整数,例如:传入10的话,则容量为16

  • HashMap的插入原理

  • 在JDK1.8之前,HashMap使用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间,红黑树转链表的阈值是6

    • hash函数是通过拿到key的hashcode,然后让hashcode的高16位和低16位进行异或操作,这样设计的原因是尽可能地减小hash碰撞,其二是位运算比较高效
  • hashmap如果采用头插法的话,在多线程的情况下会产生环,并且hashmap在多线程下也是不安全的,在JDK8之前的话,是先判断扩容再插入的,而JDK8之后则是先插入再判断是否需要扩容,扩容为扩容到原数组大小的2倍

    • 扩容的时候1.7需要对原数组中的元素进行重新hash定位在新数组的位置,1.8采用更简单的判断逻辑,位置不变或索引+旧容量大小
    • 链表转红黑树,并不是达到8个Node节点的阈值就进行转换,而是要判断一下整个数据结构中的Node数量是否大于64,大于才会转,小于就会用扩容数组的方式代替红黑树的转换

扩展

Java中有HashTable、Collections.synchronizedMap、以及ConcurrentHashMap可以实现线程安全的Map。

  1. HashTable是直接在操作方法上加synchronized关键字,锁住整个数组,粒度比较大;
  2. Collections.synchronizedMap是使用Collections集合工具的内部类,通过传入Map封装出一个SynchronizedMap对象,内部定义了一个对象锁,方法内通过对象锁实现;
  3. ConcurrentHashMap使用分段锁,降低了锁粒度,让并发度大大提高。

你可能感兴趣的:(关于Java集合的部分复习知识点整理)