zoukankan      html  css  js  c++  java
  • JDK12下的ArrayList源码解读 与 Vector的对比

    ArrayList源码阅读.

    //测试代码实现如下 
    private static void arrayList() {
    		ArrayList<String> list = new ArrayList<String>();
    		list.add("aaa");
    		list.add("bbb");
    		list.add("ccc");
    		list.add("ddd");
    		list.add("aaa");
    		list.add("bbb");
    		list.add("ccc");
    		list.add("ddd");
    		list.add("aaa");
    		list.add("bbb");
    		list.add("ccc");
    		list.add("ddd");
    		list.add(1, null);
    		int size = list.size();
    		for (int i = 0; i < size; i++) {
    			System.out.println(list.get(i));
    		}
    	}
    

    查看ArrayList<String>();的源码的时候可以发现如下:

    1. 其属性elementData被初始化为一个空的Object数组.
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    

    执行list.add("aaa");可以看到如下源码:

    1. 其中的size表示目前List中已经存储的元素的数量,目前为0.

    2. 开始执行添加元素操作.add(e, elementData, size);

    protected transient int modCount = 0;
    transient Object[] elementData; // non-private to simplify nested class access
    private int size;
    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }
    

    进入add(e, elementData, size);可以看到如下源码:

    1. 已存储元素和当前的对象数组的长度相等,都是0.

    2. 执行数组扩容行动elementData = grow();

    3. 当目前对象数组已满时得到,size==elementData.length.

    4. 进入elementData = grow();,继续扩容.

    5. 通过最后两行代码给对象数组赋值.

    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }
    

    进入elementData = grow();可以看到如下源码:

    1. grow()函数 调用grow(int minCapacity)函数,其中传参的值,是目前需要的最小空间值.

    2. 在经过newCapacity的计算之后将 新的对象数组的值,copy到elementData中.由此便完成了第一次扩容.

    3. 最小值更新minCapacity为11

    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                            newCapacity(minCapacity));
    }
    private Object[] grow() {
        return grow(size + 1);
    }
    

    进入newCapacity(minCapacity)可以看到如下源码:

    1. oldCapacity旧容量的值设置为对象数组的长度,newCapacity新容量的值设置为老容量+老容量的一次右移运算.

    2. 操作了半个小时结果发现newCapacity为0,然后进入if循环,发现目前的elementData一点没动,其地址还是最初的时候赋值的DEFAULTCAPACITY_EMPTY_ELEMENTDATA.

    3. 在默认容量DEFAULT_CAPACITY=10和最小容量minCapacity=1之间选择一个最大值,也就是10.作为返回值.

    4. newCapacity在经过右移运算后为15 . 然后执行就以15为最新的扩容值为准 返回.

    private static final int DEFAULT_CAPACITY = 10;
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }
    


    Vector的源码和ArrayList对比只有一点的不同, 那就是Vector在添加元素的时候加了线程锁, 是线程安全的.

    public synchronized boolean add(E e) {
        modCount++;
        add(e, elementData, elementCount);
        return true;
    }
    
    
    

    总结: 其实就是扩容的操作解读, 赋值很简单. 而且源码的条例就是比我们自己写的好得多.

  • 相关阅读:
    MySQL命令 导出 数据和结构
    Maven web 项目工程的建立
    Maven的配置以及Eclipse的设置
    项目管理工具Maven的安装
    centos7 安装 redis
    Java + 腾讯邮箱 SSL加密问题 重要通知
    centos7 上配置Javaweb---MySQL的安装与配置、乱码解决
    关于阿里云Centos服务器搭建Java网站不能访问的问题
    浏览器使用经验
    Linux常用命令大全
  • 原文地址:https://www.cnblogs.com/A-FM/p/10970743.html
Copyright © 2011-2022 走看看