1. <br />![](https://cdn.nlark.com/yuque/0/2021/jpeg/224303/1631103701444-74ec1fff-a4ce-42b1-8b17-36a111f7574c.jpeg)

一、List

1、ArrayList

  • 容量不够,新的容量将会是 size * 1.5 ,源码如下,附带部分注释进行解读:
  1. public boolean add(E e) {
  2. // size 表示当前线性链表中的实际元素数量
  3. ensureCapacityInternal(size + 1); // Increments modCount!!
  4. elementData[size++] = e;
  5. return true;
  6. }
  7. private void ensureCapacityInternal(int minCapacity) {
  8. // 如果数组为空,那么初始化数组大小会是10
  9. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  10. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  11. }
  12. ensureExplicitCapacity(minCapacity);
  13. }
  14. private void ensureExplicitCapacity(int minCapacity) {
  15. modCount++;
  16. // 如果新增的元素所需空间 超过数组的长度 则进行数组长度增长
  17. if (minCapacity - elementData.length > 0)
  18. grow(minCapacity);
  19. }
  20. private void grow(int minCapacity) {
  21. // overflow-conscious code
  22. int oldCapacity = elementData.length;
  23. // 新的数组长度 是 old + old/2 = 1.5 * old
  24. int newCapacity = oldCapacity + (oldCapacity >> 1);
  25. if (newCapacity - minCapacity < 0)
  26. newCapacity = minCapacity;
  27. if (newCapacity - MAX_ARRAY_SIZE > 0)
  28. newCapacity = hugeCapacity(minCapacity);
  29. // minCapacity is usually close to size, so this is a win:
  30. elementData = Arrays.copyOf(elementData, newCapacity);
  31. }
  • 扩容因子为什么是1.5倍 而不是2倍或者1.2 1.8倍
    • 如果扩容因子是2倍的话 新开辟的空间永远大于等于2,那么新容量永远大于过去所有废弃的容量的总和
    • 扩容因子为什么不是固定数值,因为固定数值有可能会太大,有可能也会太小 无法有效的规避扩容次数
    • 扩容因子为什么不是1.2倍或者1.8倍,因为如果是1.5倍的话刚好是比特右移一位产生,计算快捷节省时间

2、Vector

  • 线程安全策略:

    1. // 通过synchronized关键字修饰实现线程安全
    2. public synchronized void addElement(E obj) {
    3. modCount++;
    4. ensureCapacityHelper(elementCount + 1);
    5. elementData[elementCount++] = obj;
    6. }
  • 扩容增长策略:

    • 如果定义的增长容量大于0 则按照增长容量进行增长,否则进行原容量的倍数增长
      1. private void grow(int minCapacity) {
      2. // overflow-conscious code
      3. int oldCapacity = elementData.length;
      4. int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
      5. capacityIncrement : oldCapacity);
      6. if (newCapacity - minCapacity < 0)
      7. newCapacity = minCapacity;
      8. if (newCapacity - MAX_ARRAY_SIZE > 0)
      9. newCapacity = hugeCapacity(minCapacity);
      10. elementData = Arrays.copyOf(elementData, newCapacity);
      11. }

      3、HashMap

  • hashMap的数据结构

    • 1.7 数组+链表
    • 1.8 数组+链表+红黑树
  • hashMap的扩容原理
    • 扩容为什么两倍扩容
    • 扩容因子为什么是0.75
      • 如果扩容因子是1的话容易产生哈希碰撞
      • 如果扩容因子是0.5的话不利于空间的使用
    • 扩容条件是等于 当前容量 * 扩容因子的大小即扩容
  • hashMap的线程不安全的原理 - 因为在resize()在多线程执行的情况下会出现多值覆盖情况
  • hashMap源码解析:

    • 基本属性

      1. /**
      2. * The default initial capacity - MUST be a power of two.
      3. * 初始容量是2的4次方也就是16的大小 默认
      4. */
      5. static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
      6. /**
      7. * The maximum capacity, used if a higher value is implicitly specified
      8. * by either of the constructors with arguments.
      9. * MUST be a power of two <= 1<<30.
      10. * 最大容量不能超过2的30次方
      11. */
      12. static final int MAXIMUM_CAPACITY = 1 << 30;
      13. /**
      14. * The load factor used when none specified in constructor.
      15. * 负载因子是0.75
      16. */
      17. static final float DEFAULT_LOAD_FACTOR = 0.75f;
    • 基本方法

      1. static final int tableSizeFor(int cap) {
      2. int n = cap - 1;
      3. n |= n >>> 1;
      4. n |= n >>> 2;
      5. n |= n >>> 4;
      6. n |= n >>> 8;
      7. n |= n >>> 16;
      8. return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
      9. }
      10. 该方法是 |= 该符号的意思是二进制计算中相同进制位都为0则为零,否则就是1 >>> 无符号右移,所以上述方法
      11. 是为了得到指定cap大小的最大bit位的值,举例:如果cap = 17 n = 16
      12. 也就是 二进制 10000
      13. 第一次无符号右移1 |= 的结果为 10000 |= 01000 结果是 11000
      14. 第二次无符号右移2 |= 的结果为 11000 |= 00110 结果是 11110
      15. 最终变为 11111这种模式 +1 也就是 100000 也就是 32的大小,所以cap= 17需要 32的初始容量大小
    • 核心方法 ```java final TreeNode putTreeVal(HashMap map, Node[] tab,

      1. int h, K k, V v) {
      2. // map 当前Hashmap对象
      3. //tab Hashmap对象中的table数组
      4. //h hash值
      5. // K key
      6. // V value
      7. Class<?> kc = null;
      8. boolean searched = false; //标识是否被收索过
      9. TreeNode<K,V> root = (parent != null) ? root() : this; // 找到root根节点
      10. for (TreeNode<K,V> p = root;;) { //从根节点开始遍历循环
      11. int dir, ph; K pk;
      12. // 根据hash值 判断方向
      13. if ((ph = p.hash) > h)
      14. // 大于放左侧
      15. dir = -1;
      16. else if (ph < h)
      17. // 小于放右侧
      18. dir = 1;
      19. // 如果key 相等 直接返回该节点的引用 外边的方法会对其value进行设置
      20. else if ((pk = p.key) == k || (k != null && k.equals(pk)))
      21. return p;
      22. /**
      23. *下面的步骤主要就是当发生冲突 也就是hash相等的时候
      24. * 检验是否有hash相同 并且equals相同的节点。
      25. * 也就是检验该键是否存在与该树上
      26. */
      27. //说明进入下面这个判断的条件是 hash相同 但是equal不同
      28. // 没有实现Comparable<C>接口或者 实现该接口 并且 k与pk Comparable比较结果相同
      29. else if ((kc == null &&
      30. (kc = comparableClassFor(k)) == null) ||
      31. (dir = compareComparables(kc, k, pk)) == 0) {
      32. //在左右子树递归的寻找 是否有key的hash相同 并且equals相同的节点
      33. if (!searched) {
      34. TreeNode<K,V> q, ch;
      35. searched = true;
      36. if (((ch = p.left) != null &&
      37. (q = ch.find(h, k, kc)) != null) ||
      38. ((ch = p.right) != null &&
      39. (q = ch.find(h, k, kc)) != null))
      40. //找到了 就直接返回
      41. return q;
      42. }
  1. //说明红黑树中没有与之equals相等的 那就必须进行插入操作
  2. //打破平衡的方法的 分出大小 结果 只有-1 1
  3. dir = tieBreakOrder(k, pk);
  4. }
  5. //下列操作进行插入节点
  6. //xp 保存当前节点
  7. TreeNode<K,V> xp = p;
  8. //找到要插入节点的位置
  9. if ((p = (dir <= 0) ? p.left : p.right) == null) {
  10. Node<K,V> xpn = xp.next;
  11. //创建出一个新的节点
  12. TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
  13. if (dir <= 0)
  14. //小于父亲节点 新节点放左孩子位置
  15. xp.left = x;
  16. else
  17. //大于父亲节点 放右孩子位置
  18. xp.right = x;
  19. //维护双链表关系
  20. xp.next = x;
  21. x.parent = x.prev = xp;
  22. if (xpn != null)
  23. ((TreeNode<K,V>)xpn).prev = x;
  24. //将root移到table数组的i 位置的第一个节点
  25. //插入操作过红黑树之后 重新调整平衡。
  26. moveRootToFront(tab, balanceInsertion(root, x));
  27. return null;
  28. }
  29. }
  30. }

```

4、concurrentHashMap