zoukankan      html  css  js  c++  java
  • Java 集合 — ArrayList

    ArrayList

    • ArrayList是基于数组实现的List
    • 是有序的
    • 每次添加之前判断是否进行扩容
    • 不是线程安全的。

    构造方法

    // 空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
    // 簿制定大小的初始化,初始化为一个空数组
    public ArrayList() {
    	// super 方法为空
        super();
        // 初始化list为一个空数组,在add的ensureCapacityInternal进行初始化
        this.elementData = EMPTY_ELEMENTDATA;
    }
    
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
    	// 将list初始化为制定大小                                           
        this.elementData = new Object[initialCapacity];
    }
    
    // 从一个collection创建一个list
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        // http://blog.csdn.net/aitangyong/article/details/30274749
        // 大致意思就是c.toArray返回的不一定是Object[],所以需要进行判断
        if (elementData.getClass() != Object[].class)
        	// 如果不是Object数组复制到一个Object数组
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }
    
    

    add

    在查看add方法之前,先看看ArrayList父类AbstractList的一个属性modCount
    protected transient int modCount = 0;
    modCount是用来记录list改变的次数(add,remove,addAll etc.),这个值是被Iterator和ListIterator使用,用来检查在遍历list的时候list是否发生变化,也就是是否存在并发访问的情况。如果一个线程在遍历的时候,另一个线程进行add和remove,会造成遍历出错抛出ConcurrentModificationException

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    
        ensureExplicitCapacity(minCapacity);
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
    	// 每次add的时候都会增加modCount
        modCount++;
    
        // overflow-conscious code
        // 如果原来的数组已经满了,则进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    // list扩容
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 每次扩容为原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        	// 当一开始数组大小为1的时候会出现,即elementData.length = 1
            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);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
        	// minCapacity可能会溢出,Integer.MAX_VALUE + 1就是负的
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
    

    get

    public E get(int index) {
    	// 检查数组下标是否越界
        rangeCheck(index);
    	// 使用数组下标直接访问
        return elementData(index);
    }
    

    set 替换原来index位置的元素

    public E set(int index, E element) {
        rangeCheck(index);
    
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
    

    remove

    public E remove(int index) {
        rangeCheck(index);
    	// 删除的时候也需要对modCount加1,因为modCOunt记录的是list的改变次数,remove也会改变list
        modCount++;
        // 记录下被删除的元素,下面返回
        E oldValue = elementData(index);
    
        int numMoved = size - index - 1;
        if (numMoved > 0)
        	// copy的时候跳过要删除的元素
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    
        return oldValue;
    }
    
  • 相关阅读:
    Apache Pig使用MongoLoader产生大量空文件问题
    执行sparksql出现OOM问题
    [TD笔记]Teradata XML
    Redhat上离线/非root安装python库
    Java 多线程同步关键字synchronized各种用法/特性 总结
    CVE-2019-0708 微软远程桌面服务远程代码执行漏洞分析之补丁分析
    Spring Security 实战(使用Spring Boot项目演示)
    一些渗透中,或者扫描的nmap nse脚本推荐
    kali学习笔记(一):虚拟机安装好kali后应进行的配置
    Spring boot相关问题
  • 原文地址:https://www.cnblogs.com/sunshine-2015/p/6115867.html
Copyright © 2011-2022 走看看