Java8源码学习 - ArrayList

类声明:

public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializablepublic interface RandomAccess {}

这个接口是一个标记接口,表明其支持快速的随机访问,也就是通过索引下标能否快速的移动到对应的元素上.主要是允许通过算法来更改其的行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。

在程序遍历的时候很多情况下不知道是使用for还是foreach或iterator。

在更多的时候都是选择比较简略的foreach()或则for,其实遍历方式的选择与遍历效率有明显联系

而对一个实现  RandomAccess 接口的list而言,使用for()循环,遍历效率比另外两种都要高不少

在判断一个list选择何种方式遍历时,我们可以这样: 

if (list instanceof RandomAccess) {   for(int m = 0; m < list.size(); m++){}}else{   Iterator iter = list.iterator();   while(iter.hasNext()){}}

成员变量

private static final long serialVersionUID = 8683452581122892189L;
    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;
    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};
    /**
     *默认的elementData,当使用无参构造器时会将此数组实例对象的引用给elementData
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    /**
       内部容器--储存元素
     */
    transient Object[] elementData; // non-private to simplify nested class access
    /**
     * The size of the ArrayList (the number of elements it contains).
     *当前的大小
     * @serial
     */
    private int size;
   /**

     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

ArrayList添加一个元素

/**
 * Appends the specified element to the end of this list.
*/
public boolean add(E e) {
        //判断是否扩容和扩容操作,确保添加新元素后容量足够
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
}
//保证添加元素之后数组容量在范围之内
private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果使用无参构造器得到arraylist实例,没有指定初始容量
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
            //minCapacity:最小的扩容值--当前数组的长度小于minCapacity则扩容
        ensureExplicitCapacity(minCapacity);
}
 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
}
/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *扩充这个数组的容量确保他能够容下最小容量参数所指定的元素
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//新的数组的容量 = 数组的容量 + 数组的容量/2
        if (newCapacity - minCapacity < 0)//保证新的数组的大小一定比原数组的大小大
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//如果新的数组的大小超过array的最大的大小(maximum size of array),进行最后的扩容+8  
                 newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        //如果复制数组_关于复制数组的几种方式的效率_参考:http://blog.csdn.net/tingzhiyi/article/details/52344845
        elementData = Arrays.copyOf(elementData, newCapacity);
        //Arrays.copyOf--实际调用的是system的System.arraycopy(...)方法属于浅复制,使用的时候需要注意
        ---------------------------------------------------------------------------------------------------------
         List<Object>  list = new ArrayList<>();
         //分别为list增加一个对象和一个string
         list.add(new TestOne()); //TestOne是一个class
         list.add("aaa");
          
          Object [] ss =  list.toArray();//list.toArray()也是由system的System.arraycopy(...)方法实现
           //改变新的数组的值
          ((TestOne)ss[0]).setA("aa");
          ((TestOne)ss[0]).setA1(4);
          System.out.println(list.toString());
          ss[1] = "bbb";
          
          System.out.println(ss[0].toString()+":"+ss[1].toString());
          System.out.println(list.get(0)==ss[0]);
          System.out.println(list.get(1)==ss[1]);
         result://复制并不会新增堆中的实例对象,只有新增一个指向该实例的一个引用
          [TestOne [a=aa, a1=4], aaa]
          TestOne [a=aa, a1=4]:;;;bbb
          true
          false
         ---------------------------------------------------------------------
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }  

ArrayList的clone方法

/**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
       返回这个ArrayList实例的浅拷贝————其元素本身不被复制,即复制引用_
        想要其实现深拷贝只需在其涉及的所有引用类型的引用的类
                             都实现java.lang.Cloneable接口和都重写java.lang.Object.clone()方法
                在clone方法中调用super.clone()返回
      或对象序列化和反序列化实现深拷贝
     * @return a clone of this <tt>ArrayList</tt> instance
     */
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
-------------------------------------------------------------------------------------
         List<Object>  list = new ArrayList<>();
         list.add(new TestOne());
         list.add("aaa");
         List<Object>  list22 = (List<Object>) ((ArrayList)list).clone();
          ((TestOne) list22.get(0)).setA("bb");
          ((TestOne) list22.get(0)).setA1(5);
          list22.set(1, 8);
          System.out.println(list22.get(0)==list.get(0));
          System.out.println(list22.get(1)==list.get(1));
         =====>
             true
             false

ArrayList的remove方法

/**  根据索引删除元素
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
       将数组此索引的后面的元素直接复制到索引开始位置到结束(后面的元素都左移一位),然后将最后面的元素置null方便GC
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
public E remove(int index) {
        rangeCheck(index);
        modCount++;
        E oldValue = elementData(index);
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work//数组的元素个数减一,length不变
           
        return oldValue; //返回删除的元素的值
    }
 /** 根据value删除第一个出现的元素,如果此value不存在则不改变 
     */
    public boolean remove(Object o) {
        //equals调用则不能为null
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    //此方法与remove(int index)类似,没有返回值
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
    注意:每次删除一个元素,其size都会减1,那么循环删除多个arraylist元素的时候不能单纯的使用size
    如: for(int i = 0; i < list.size();i++){
                //.....
                list.remove(i);
       }
             
    在remove一条信息时,
     ArrayList的大小已经改变(即list.size()已经改变);
     在i大于等于list.size()时,循环跳出,后面的ArrayList不能再执行;
     所以必须在remove的同时,执行i--,即i=i-1;
     现在才能遍历所有List中的信息。也不能在用Iterator遍历时使用remove,会抛异常。
    /**
     * 清空:将储存数组的value全部置null
     */
    public void clear() {
        modCount++;
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
    }

ArrayList的sublist方法


/**
     * Returns a view of the portion of this list between the specified
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
     * empty.)  The returned list is backed by this list, so non-structural
     * changes in the returned list are reflected in this list, and vice-versa.
     * The returned list supports all of the optional list operations.
     *返回list的一部分视图,如果开始位置和结束位置一样则返回空的list,
      返回的list没有结构,仅仅是目标list的一部分,两个一体,改变一个另一个也会改变
      返回的list支持list所有的操作
     * <p>This method eliminates the need for explicit range operations (of
     * the sort that commonly exist for arrays).  Any operation that expects
     * a list can be used as a range operation by passing a subList view
     * instead of a whole list.  For example, the following idiom
     * removes a range of elements from a list:
     * <pre>
     *      list.subList(from, to).clear();
     * </pre>
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws IllegalArgumentException {@inheritDoc}
     */
    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);//一个范围检查
        return new SubList(this, 0, fromIndex, toIndex);
    }
   //SubList 是arrayList的一个私有的内部类,其内部对list的操作都是在外部类的elementdata上进行的
    private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;//表示它的外部类的引用
        private final int parentOffset;//索引开始位置—不需要记录索引的结束位置,可size可以表示索引的结束位置
        private final int offset;//当前索引位置—
        int size;//记录此视图元素的数量
        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }
   }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨中漫步t2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值