• JAVA常用集合解析


    ArrayList :
    底层基于数组实现,在使用add方法添加元素时,首先校验集合容量,将新添加的值放入集合尾部并进行长度加一,进行自动扩容,扩容的操作时将数据中的所有元素复制到新的集合中。

    在指定位置添加元素时
    public void add(int index, E element) {
    检查索引是否为0或者超出集合长度
    rangeCheckForAdd(index);
    将集合扩容,长度加1
    ensureCapacityInternal(size + 1); // Increments modCount!!
    //从指定index位置开始将其后元素向后移动一位,空余出index位置
    System.arraycopy(elementData, index, elementData, index + 1,
    size - index);
    给index赋值
    elementData[index] = element;
    size++;
    }

    从 ensureCapacityInternal 延申到此方法
    private void grow(int minCapacity) {
    // overflow-conscious code
    //校验长度后
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //会进行复制集合操作
    elementData = Arrays.copyOf(elementData, newCapacity);
    }
    由此可见在创建arrayList集合时最好提前预估长度,以免不必要的扩容,提高性能。

    transient Object[] elementData; 集合中加transient是防止被自动序列化。因为arrayList是基于动态数组,可能不会使用数组的全部空间,在它的类中重写了序列化和反序列化方法

    HashMap: 线程不安全, 默认大小为16 负载因子0.75 当集合中元素大于 16*0.75时就会发生扩容。
    使用put方法后,会计算出key的hash值,然后根据数组长度取模运算出存放下标。
    在数组长度有限的情况下会出现计算下标一致的情况(hash冲突)那么会在此
    形成链表,采用头插法插入。当hash冲突严重时就会形成很长的链表,导致
    查询效率低下。
    在jdk1.8中,判断如果链表中元素长度如果大于8那么就将
    链表转换为红黑树,从而优化的查询效率,由O(n)变为0(logn)

    get方法,使用key值计算下标,如果下标相同,遍历链表调用equals()方法比较。
    在多线程中使用时,并发扩容时会导致形成环形链表,假如在寻找一个不存在的key时找到环形链表的index会出现死循环。

    未完待续。。

  • 相关阅读:
    线程池类型场景和问题
    react Antdesign Select添加全选功能
    API与ESB 、ServiceMesh、微服务究竟关系如何?
    RabbitMQ四种Exchange类型
    RabbitMq安装
    kafka 部署
    共享文件夹重启后每次都要输入密码
    algorithm 12 partial_sort_copy
    algorithm 11 nth_element
    algorithm 11 none_of
  • 原文地址:https://www.cnblogs.com/CHWLearningNotes/p/9714328.html
Copyright © 2020-2023  润新知