ArrayList笔记

  1. 成员变量
   /**
     * 默认初始化大小,如果不指定,则底层存储结构默认为一个长度为10个存储单位的数组
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空数组,用户传入为0,则使用此数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 默认数组,当使用无参构造时使用此数组
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 存储该ArrayList数据对象的数组
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * 该ArrayList数组中实际元素的个数
     */
    private int size;

  1. 构造方法

    /**
     * 有参构造,参数为非负整数
     * 根据传入的整型数字,来构造一个对应大小的数组
     */
    public ArrayList(int initialCapacity) {
        //step1.如果传入初始化容量大于0,则创建一个对应大小的数组
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        //step2.如果传入初始化容量等于0,则使用默认为空的数组
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        //step3.其他情况皆异常
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        }
    }

    /**
     * 无参构造方法,创建一个默认的长度为10的空数组
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 根据集合来进行构造ArrayList
     */
    public ArrayList(Collection<? extends E> c) {
        //step1.集合转为数组
        elementData = c.toArray();
        //step2.如果此数组长度不等于0,拷贝为一个object数组
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        //step3.其他情况都使用空数组
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
  1. 添加元素(动态扩容机制)
 /**
  * 向ArrayList添加一个元素 
  */
public boolean add(E e) {
        //step1.确定容量,扩容
        ensureCapacityInternal(size + 1);  
        //step2.添加元素
        elementData[size++] = e;
        //step3.添加成功
        return true;
 }
/**
  * 扩容
  */
private void ensureCapacityInternal(int minCapacity) {
       ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
 }
 
/**
 * 获取最小扩容
 * 添加第一个元素前底层数组容量为0
 * 添加第一个元素后底层数组容量成为了10
 */
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
}

/**
  * 根据所需最小扩容量来判断是否需要扩容
  */
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        //minCapacity为数组中实际元素的个数,而不是数组长度
        //当第1次添加元素的时候,此时minCapacity=1 elementData.length=0,经过calculateCapacity(Object[] elementData, int minCapacity),返回为10,此时入参minCapacity=10,扩容一次
        //当第2次添加元素时候,此时minCapacity=2,elementData.length=10,经过calculateCapacity(Object[] elementData, int minCapacity),返回为2,此时入参minCapacity=2,不会扩容
        //当第3,4,...,10次添加元素时,minCapacity - elementData.length > 0 不成立,不会扩容
        //直到第11次,minCapacity - elementData.length > 0 成立,再次扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

 /**
  * ArrayList真实扩容方法
  **/
 private void grow(int minCapacity) {
        // step1.计算原始容量
        int oldCapacity = elementData.length;
        //step2.计算新容量以1.5倍来扩容,采用位运算,右移1位位原来数字的0.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //step3.如果新容量小于最小所需容量,则使用最小容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //step4.如果新容量大于ArrayList分配的容量大小,则计算最小容量与ArrayList最大容量的大小
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //step5.拷贝新List
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

 /***
  **计算最小容量与ArrayList最大容量的大小
  ***/
 private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

ArrayList扩容中用到了位移运算

int newCapacity = oldCapacity + (oldCapacity >> 1);

包括HashMap中的哈希寻址算法,计算哈希值右移16位,将高低16进行异或运算,大大提高了运算效率

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

HashMap添加元素计算哈希地址时也取模运算

(n - 1) & hash

也采用了逻辑操作

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值