[直击native] 单步调试ArrayList 源码 一

[直击native] 单步调试ArrayList 源码 一

源码版本 jdk 1.8
源码调式过程中需要不停的进入函数内部,函数内部的函数 根据调试顺序在当前函数的后面
如果调试函数调用的是完全相同函数 则不再赘述
详细调试从ArrayList 对象初始化开始

类继承关系

在这里插入图片描述

主要public 方法

在这里插入图片描述

基础方法解读

测试代码




    @Test
    public void createList() {
        List<String> arr1 = new ArrayList<>();
        arr1.add("12222222");
        List<String> arr2 = new ArrayList<>(10);
        List<String> arr3 = new ArrayList<>(arr1);
    }

    @Test
    public void arrayConvertTest() {
        class MyArr extends ArrayList {
            @Override
            public String[] toArray() {
                return new String[]{"123"};
            }
        }
        List<String> arr = new MyArr();
        Object[] objects = arr.toArray();
        objects[0] = new Object();

    }

    @Test
    public void arrayCreateCompareTest() throws ClassNotFoundException {
        //创建空数组
        Object[] numbers = (Object[]) new Object[10];
        // stringClass  componentType 等价
        Class<String> stringClass = String.class;
        Class<?> componentType = String[].class.getComponentType();
        //动态创建空数组
        String[] strings = (String[]) Array.newInstance(componentType, 10);
        for (Object number : numbers) {
            System.out.println(number);
        }
        for (String string : strings) {
            System.out.println(string);
        }
        //全部是空数组
    }

    @Test
    public void classCompareTest() {
        Class newType = Object[].class;
        Class newType1 = String[].class;
        //true
        System.out.println((newType == Object[].class));
        //true
        System.out.println(((Object) newType == (Object) Object[].class));
        //false
        System.out.println((newType1 == Object[].class));
        //false
        System.out.println(((Object) newType1 == (Object) Object[].class));
    }

    //等价
    public static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        //这一行强转可以不需要 ,在下面 测试代码 jdk 8 运行下与不强转等价
        //https://stackoverflow.com/questions/29494800/do-not-understand-the-source-code-of-arrays-copyof
        //根据上面介绍 这个强转可能是为了更好的兼容低版本 和性能加的 强转
        Object newTypeObject = (Object) newType;
        T[] copy = null;
        if (newTypeObject == (Object) Object[].class) {
            //如果是已知的object 数组 直接new
            copy = (T[]) new Object[newLength];
        } else {
            //如果不是已知的则 使用动态的方法 创建对应类型空数组
            //其引用的 是底层的native 方法
            copy = (T[]) Array.newInstance(newType.getComponentType(), newLength);
        }
        //获得空数组之后 从original 的0 位置开始复制 到copy 取最小的一个值(代表有数据,空值不用赋值了)
        //这里 同样是调用 底层的 native 方法
        System.arraycopy(original, 0, copy, 0,
                Math.min(original.length, newLength));
        //最后返回复制得到的新数组 , 可以知道是 大容量 同样数据的新数组
        return copy;
    }

    @Test
    public void addElementToArrayList(){
        // 添加元素 变化不同情况 在 分析构造器时提到  elementData 在第一次添加时会扩展到默认大小
        // 所以用两个构造器分别添加元素测试
        // 查看添加过程代码

        List<String> arr1 = new ArrayList<>();
        arr1.add("12222222");
        arr1.add("12222222");
        arr1.add(0,"12222222");
        // IndexOutOfBoundsException
        //arr1.add(7,"12222222");

        List<String> arr2 = new ArrayList<>();

        arr2.addAll(arr1);

        arr2.addAll(2,arr1);

    }

    @Test
    public void arraycopyTest(){
        Integer[] src = new Integer[5];
        src[0] = 20;
        src[1] = 21;
        src[2] = 22;
        src[3] = 23;
        Integer[] dest = new Integer[5];
        System.arraycopy(src,0,dest,1,3);
        for (Integer integer : src){
            System.out.println(integer);
        }
        System.out.println();
        for (Integer integer : dest){
            System.out.println(integer);
        }
        /***
         * 20
         * 21
         * 22
         * 23
         * null
         *
         * null
         * 20
         * 21
         * 22
         * null
         */
    }

    @Test
    public void setElementTest(){
        List<String> arr = new ArrayList<>();

/*
        arr.add("1");
        arr.add("2");
        arr.add("3");
*/

        String set = arr.set(2, "6");
        System.out.println(set);


    }

    @Test
    public void removeTest() {
        List<String> arr = new ArrayList<>();
        String string = new String("123");
        arr.add(string);
        arr.add(string);

//        arr.remove(1);

        arr.removeAll(arr);

        for (String s:arr  ) {
            System.out.println(s);
        }

        arr.clear();

    }

    @Test
    public void getTest(){
        List<String> arr = new ArrayList<>();
        String string = "123";
        arr.add(string);
        arr.add(string);

        String s = arr.get(0);

        int indexOf = arr.indexOf(string);


        int lastIndexOf = arr.lastIndexOf(string);

        boolean contains = arr.contains(arr);

        boolean containsAll = arr.containsAll(arr);

    }
        





ArrayList 对象初始化

空参构造

//空参 默认赋值 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 给elementData 缓冲取元素数组


   /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
//下面是几个源码中常用内部变量

    /**
     * 默认容量 10 
     */
    private static final int DEFAULT_CAPACITY = 10;

	/**
     * 空元素 对象数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     * 空元素 对象数组 这个是默认的 与上面的空数组 区分
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     * 这个是ArrayList 底层的存储结构 容量为 数组长度 
     	空数组 默认等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     	当第一个元素添加的时候 拓展到默认容量
     */
    transient Object[] elementData; // non-private to simplify nested class access



注释写道: 初始化默认elementData 为 空数组 当第一个元素添加 将扩容到默认容量

带参构造函数

其中指定容量构造方法是 推荐使用的

// 这个可以指定一个集合传入,必须是含有e的子类的 Collection的子类
    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        // 列表转换成 数组 调用的为 Collection<? extends E> 集合的 方法 
        // 也正是因为这里的 toArray 具体实现不可空 所以下面代码产生了 bug 6260652
        // 判断也正是为了修复这个bug 
        elementData = c.toArray();
        // 此处:调用 返回的是 对象数组或对象子类数组 直接赋值给这个arraylist 缓冲区数组  
        if ((size = elementData.length) != 0) {
            //先将size 设置为 缓冲数组长度 并且如果不为零
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            //此处判断是否为对象数组 
            //比如:     
            //class MyArr extends  ArrayList{
            //    @Override
            //    public String[] toArray(){
            //        return new String[]{"cc190911"};
            //    }
        	//}
        	//List<String> arr = new MyArr();
       		//Object[] objects = arr.toArray();
        	//objects[0] = new Object();  
            //java.lang.ArrayStoreException: java.lang.Object
            //如果不为对象数组则 使用底层的Arrays 工具类重新赋值
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {//为零则将空数组赋值给缓冲数组
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
    

	//指定容量
    /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {//如果大于零
            this.elementData = new Object[initialCapacity];//赋值为容量大小数组
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;//为零则是空数组 , 如上
        } else {//否则抛出非法参数 异常 非法容量 
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }



Arrays 底层方法

此方法是后续实现数组动态扩容的重要方法


/**
复制指定的数组,截断或用空填充(如有必要),以便复制具有指定的长度。
对于在原始数组和副本中都有效的所有索引,这两个数组将包含相同的值。
对于副本中有效但不是原始索引的任何索引,副本将包含<tt>null</tt>。
当且仅当指定的长度大于原始数组的长度时,才存在此类索引。
得到的数组是类<tt>newType</tt>。
 * Copies the specified array, truncating or padding with nulls (if necessary)
 * so the copy has the specified length.  For all indices that are
 * valid in both the original array and the copy, the two arrays will
 * contain identical values.  For any indices that are valid in the
 * copy but not the original, the copy will contain <tt>null</tt>.
 * Such indices will exist if and only if the specified length
 * is greater than that of the original array.
 * The resulting array is of the class <tt>newType</tt>.
 *
 * @param <U> the class of the objects in the original array 原始数组中对象的类
 * @param <T> the class of the objects in the returned array 返回数组中对象的类
 * @param original the array to be copied 初始化要复制的数组
 * @param newLength the length of the copy to be returned 要返回的副本的长度
 * @param newType the class of the copy to be returned 要返回的副本的类
 * @return a copy of the original array, truncated or padded with nulls
 *     to obtain the specified length 原始数组的副本,截断或用空填充以获得指定长度
 * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
 * @throws NullPointerException if <tt>original</tt> is null
 * @throws ArrayStoreException if an element copied from
 *     <tt>original</tt> is not of a runtime type that can be stored in
 *     an array of class <tt>newType</tt>
 * @since 1.6
 */
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

    //等价
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        //这一行强转可以不需要 ,在下面 测试代码 jdk 8 运行下与不强转等价
        //https://stackoverflow.com/questions/29494800/do-not-understand-the-source-code-of-arrays-copyof
        //根据上面介绍 这个强转可能是为了更好的兼容低版本 和性能加的 强转
        Object newTypeObject = (Object)newType;
        T[] copy = null;
        if (newTypeObject== (Object)Object[].class){
            //如果是已知的object 数组 直接new
            copy = (T[]) new Object[newLength] ;
        }else{
            //如果不是已知的则 使用动态的方法 创建对应类型空数组
            //其引用的 是底层的native 方法
            copy = (T[]) Array.newInstance(newType.getComponentType(), newLength);
        }
        //获得空数组之后 从original 的0 位置开始复制 到copy 取最小的一个值(代表有数据,空值不用赋值了)
        //这里 同样是调用 底层的 native 方法
        System.arraycopy(original, 0, copy, 0,
                Math.min(original.length, newLength));
        //最后返回复制得到的新数组 , 可以知道是 大容量 同样数据的新数组
        return copy;
    }
  
    @Test
    public void classCompareTest(){
        Class newType = Object[].class ;
        Class newType1 = String[].class ;
        //true
        System.out.println((newType==Object[].class));
        //true
        System.out.println(((Object) newType==(Object) Object[].class));
        //false
        System.out.println((newType1==Object[].class));
        //false
        System.out.println(((Object) newType1==(Object) Object[].class));
    }

ArrayList添加元素

以下方式添加方法

  • 添加元素 到最后位置
  • 添加元素 到固定位置
  • 添加集合类全部元素到最后位置
  • 添加集合类全部元素到指定位置

[外链图片转存失败(img-J3ZLEjly-1568275586616)(1568100863519.png)]

  /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        // 确保容量范围内
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 把对象赋值到  当前数组的位置 并将size + 1   
        elementData[size++] = e;
        return true;
    }
	//确保容量在范围内
    private void ensureCapacityInternal(int minCapacity) {
        // 此处 可以看到 如果elementData是DEFAULTCAPACITY_EMPTY_ELEMENTDATA(默认空)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 扩容到DEFAULT_CAPACITY minCapacity 较大的一个
            // 直接空参初始化 size = 0  minCapacity = 1
            // 所以直接是最小容量为DEFAULT_CAPACITY = 10 
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
		
        ensureExplicitCapacity(minCapacity);
    }

	// 确保显性容量
    private void ensureExplicitCapacity(int minCapacity) {
     	// 修改次数加一 
        // 在 java.util.AbstractList
        //     protected transient int modCount = 0;
        // 这是个很重要的变量 , 后面讲到
        modCount++;
        
        // 自动增长 , 如果传递的minCapacity需要最小的容量 比当前缓冲的对象数组大
        // 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;
        // 新容量 = 长度 + 长度右移1位(长度一半) 
        // 这里也是为什么 新的容量是 之前的1.5倍
        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:
        // 这样处理 可以使 最小值 尽可能接近 大小 这样可以节省内存空间
        // 还是调用数组动态赋值函数如下 , 其底层还是调用
        // copyOf(original, newLength, original.getClass())
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

	// 大容量 函数计算
    private static int hugeCapacity(int minCapacity) {
        // 如果小于零 溢出错误
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        // 如果 最小容量大于最大数组大小 则返回 整型最大值 
        // 否则 还是 返回 最大最大数组大小
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
	// 最大数组大小 为 整形最大值 - 8 
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
	// Integer.MAX_VALUE 
    @Native public static final int   MAX_VALUE = 0x7fffffff;

	//Arrays 的函数 
	public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }


  	/**
  		将指定元素插入到列表中的指定位置。
  		将当前位于该位置的元素(如果有的话)和随后的任何元素向右移动(将一个元素添加到它们的索引中)。
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        // 检查 是否越界
        rangeCheckForAdd(index);
		// 大小加一 后 确保在容量内 
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 调用底层函数 复制
        // 从当前长度 size - index 的 elementData的index 复制到 elementData的index + 1 
         System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        // 将index 位置赋值为当前元素
        elementData[index] = element;
        // 大小加一
        size++;
    }

    /**
    	检查索引异常 如果 当前检索大于 size 或者 小于 0 抛出数组越界异常
    	可见 不能在当前list的size之后位置使用add 方法 添加 元素
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
	// 这个打印 当前 越界信息
 	private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }


	/**
	按指定集合的迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾。
	如果在操作进行期间修改了指定的集合,则此操作的行为未定义。
	(这意味着,如果指定的集合是这个列表,并且这个列表不是空的,则此调用的行为是未定义的。)
     * Appends all of the elements in the specified collection to the end of
     * this list, in the order that they are returned by the
     * specified collection's Iterator.  The behavior of this operation is
     * undefined if the specified collection is modified while the operation
     * is in progress.  (This implies that the behavior of this call is
     * undefined if the specified collection is this list, and this
     * list is nonempty.)
     *
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     */
    public boolean addAll(Collection<? extends E> c) {
        // 返回 集合类中的对象数组  , 这里测试c用的 ArrayList 
        // 下面分析下 ArrayList 的toArray
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

 	/**
 		返回的是第一个到最后一个的元素数组对象
     * Returns an array containing all of the elements in this list
     * in proper sequence (from first to last element).
     * 这个返回的数组是安全的 没有任何引用  也就是重新创建的一个 新的数组
     * <p>The returned array will be "safe" in that no references to it are
     * maintained by this list.  (In other words, this method must allocate
     * a new array).  The caller is thus free to modify the returned array.
     * 这个方法充当 基础数组和基本集合类的转换桥梁
     
     * <p>This method acts as bridge between array-based and collection-based
     * APIs.
     *
     * @return an array containing all of the elements in this list in
     *         proper sequence
     */
    public Object[] toArray() {
        // 可以看到调用的是上面 Arrays.copyOf 
        // 因此的到的是一个全新的数组副本
        return Arrays.copyOf(elementData, size);
    }


    /**
    从指定位置开始,将指定集合中的所有元素插入此列表。
    将当前位于该位置的元素(如果有的话)和随后的任何元素移动到右边(增加它们的索引)。
    新元素将按指定集合的迭代器返回它们的顺序出现在列表中。
     * Inserts all of the elements in the specified collection into this
     * list, starting at the specified position.  Shifts the element
     * currently at that position (if any) and any subsequent elements to
     * the right (increases their indices).  The new elements will appear
     * in the list in the order that they are returned by the
     * specified collection's iterator.
     *
     * @param index index at which to insert the first element from the
     *              specified collection
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException if the specified collection is null
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        // 同样的 索引检测越界
        rangeCheckForAdd(index);
		// 转换成对象数组
        Object[] a = c.toArray();
        // 得到数组实际长度
        int numNew = a.length;
        // 确保 容量足够 
        // 这里 modCount 只会加1 
        ensureCapacityInternal(size + numNew);  // Increments modCount
		// 移动量  = 当前大小减 索引位置
        int numMoved = size - index;
        // 如果大于零 则特殊处理
        // 先将 elementData index 后的元素往后移动 numMoved 
        // 这里 不会出现 小于零的情况 因为前面有越界检测
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
        // 移动之后就相当于等于零
		// 将需要添加的数组numNew长度赋值到 	elementData 的 index位置和之后
        System.arraycopy(a, 0, elementData, index, numNew);
        // 当前大小增大 numNew 
        size += numNew;
        // 长度不为0 则成功 其实和之前直接返回 true 差不多
        // 不过也需要注意一下 如果长度为零 返回的是false
        return numNew != 0;
    }



ArrayList 修改元素

修改元素使用的是set(int index, E element) , 与添加不同的是它只有一个函数

上面有个问题是,如果添加元素在当前数组之外 , 容量之内 是不能添加的

那么,set 是否可以呢?

  /**
  		用指定的元素替换列表中指定位置的元素。
     * Replaces the element at the specified position in this list with
     * the specified element.
     *
     * @param index index of the element to replace 要替换的元素的索引
     * @param element element to be stored at the specified position 要存储在指定位置的元素
     * @return the element previously at the specified position 先前位于指定位置的元素
     * @throws IndexOutOfBoundsException {@inheritDoc} 数组越界异常
     */
    public E set(int index, E element) {
        // 看到这个check 函数 应该就猜到 可能有越界检测
        // 所以函数在数组没有任何值的时候是不能使用set 方法的
        rangeCheck(index);
		// 获取实际元素类型的对象 
        E oldValue = elementData(index);
        // 将元素存入
        elementData[index] = element;
        // 返回之前在这个位置的元素
        return oldValue;
        // 函数结束 没有修改 modCount 值
    }


    /**
    检查给定索引是否在范围内。
    如果没有,则抛出适当的运行时异常。
    这个方法不检查索引是否为负数:它总是在数组访问之前使用,如果索引为负数,数组访问将抛出一个ArrayIndexOutOfBoundsException。
     * Checks if the given index is in range.  If not, throws an appropriate
     * runtime exception.  This method does *not* check if the index is
     * negative: It is always used immediately prior to an array access,
     * which throws an ArrayIndexOutOfBoundsException if index is negative.
     */
    private void rangeCheck(int index) {
        // 这里只判断了 是否 大于数组大小 
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

 // Positional Access Operations
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        // 里面就是常见的 下标获取 
        // 只是添加了类型强转 , 将之前存入的类型 还原
        return (E) elementData[index];
    }


ArrayList 删除元素

删除元素有三个方法

public E remove(int index) ; 指定索引删除,会返回指定位置的元素

public boolean remove(Object o) ;//指定元素删除 ,返回是否成功删除

public boolean removeAll(Collection<?> c) ;//指定集合删除,返回是否成功删除

public void clear() ; // 删除全部



    /**
    移除列表中指定位置的元素。将任何后续元素向左移动(从它们的索引中减去一个)。
    
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @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;
        // 如果大于0 就需要往左移numMoved 位
        // 所以 如果这个相对位移越大 消耗的时间也是越多的
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 因为左移之后 最右边和最右边的左边一位是相同
        // 所以先将元素置null 然后将大小减一 
        // 置null 是为了jvm gc 这里涉及到jvm 的gc 工作原理 
        // 可以理解为如果对象有引用的话 jvm内存管理认为这些对象还在使用 所以不会那么快释放(实际已经是无用对象) 
        // 所以在集合类使用过程中 尽量使用之后也将其置null 
        // 如: list = null;
        elementData[--size] = null; // clear to let GC do its work
		// 返回 之前位置对象
        return oldValue;
    }

 	/**
 	
 	从列表中删除指定元素的第一个出现项(如果存在)。
 	如果列表不包含该元素,它将保持不变。
 	更正式地说,删除索引最低的元素<tt>i</tt>,
 	使<tt>(o==null ? get(i)==null: o. = (get(i)) </tt>(如果存在这样一个元素)
 	。如果该列表包含指定的元素,则返回<tt>true</tt>(如果该列表由于调用而更改,则返回相同的结果)。
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
    public boolean remove(Object o) {
        // 判断是否为空 , 所以这个也是可以保存null 的 
        // 同时也为了避免后面equals npe 
        if (o == null) {
            // 遍历
            for (int index = 0; index < size; index++)
                // 如果有一个为空
                if (elementData[index] == null) {
                    // 调用私有方法 移除
                    fastRemove(index);
                    // 直接返回true 所以 移除对象的方法 只会删除最左边第一个匹配的对象
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                // 唯一不同的是调用的是存入对象的equals 方法
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        // 最后如果没有找到 则返回false
        return false;
    }

 	/*
 	私有的remove方法,该方法跳过边界检查,并且不返回已删除的值。
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        // 进来发现 是不是似曾相识
        // 和上面的 set add集合 是相似的代码结构
        // 注意的是这个方法 并没有边界检查 并且也不返回删除的值
        // 那么 为什么上面的set add 集合不调用这个函数呢?
        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
    }

  /**
  		从该列表中删除指定集合中包含的所有元素。
     * Removes from this list all of its elements that are contained in the
     * specified collection.
     *
     * @param c collection containing elements to be removed from this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
    public boolean removeAll(Collection<?> c) {
        // 一种规范性的写法:不为空判断 , jdk7 推出的 对象工具类 
        Objects.requireNonNull(c);
        // 批量移除
        // 注意这个false
        return batchRemove(c, false);
    }
/**
 * This class consists of {@code static} utility methods for operating
 * on objects.  These utilities include {@code null}-safe or {@code
 * null}-tolerant methods for computing the hash code of an object,
 * returning a string for an object, and comparing two objects.
 *
 * @since 1.7
 */
public final class Objects {
 	/**
     * Checks that the specified object reference is not {@code null}. This
     * method is designed primarily for doing parameter validation in methods
     * and constructors, as demonstrated below:
     * <blockquote><pre>
     * public Foo(Bar bar) {
     *     this.bar = Objects.requireNonNull(bar);
     * }
     * </pre></blockquote>
     *
     * @param obj the object reference to check for nullity
     * @param <T> the type of the reference
     * @return {@code obj} if not {@code null}
     * @throws NullPointerException if {@code obj} is {@code null}
     */
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }
}


    private boolean batchRemove(Collection<?> c, boolean complement) {
        // 将 elementData 对象数组 引用到 局部变量
        final Object[] elementData = this.elementData;
        //新建的两个变量,那源码中忽然看到这么奇怪命名的变量怎么办?接着往下分析.
        int r = 0, w = 0;
        // 是否修改标识 用于后面返回是否成功移除
        boolean modified = false;
        try {
            // 循环遍历对象数组 , 可以知道 r 是用于遍历对象数组 单独拿出来是因为后面也要用到
            for (; r < size; r++)
                // 判断 当前对象是否在传入集合对象中
                // 返回 true false 再与 complement 比较 
                // 如果 complement = false 当前对象不在集合类中 
                if (c.contains(elementData[r]) == complement)
                    // 则将当前对象赋值给elementData
                    // 并且是放在w下标位置 w 是新的局部变量中elementData 的下标指向
                    // 每修改一个就会往右移
                    elementData[w++] = elementData[r];
        } finally {
            // 即使c.contains()抛出异常,也要保持与AbstractCollection的行为兼容性。
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            // r不等于size,为什么会不等,那么肯定是抛出了异常
            // 可能 ClassCastException NullPointerException等
            if (r != size) {
                // 将后续没有对比的 都加入到elementData的w位置之右
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                // w 加上后续没有比较的长度
                w += size - r;
            }
            // 如果w 不等于 size ,说明在对象数组中有剔除元素
            if (w != size) {
                // 同样将剩余元素后面的数组对象 置空 help gc
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                // 增加修改次数 
                // 这里剔除多少元素 就修改多少次
                modCount += size - w;
                // 将实际大小修改为 size 
                size = w;
                // 修改成功
                modified = true;
            }
        }
        // 返回 
        return modified;
        /****
        *
        	函数结束: 所以将this.elementData 引用赋值给局部变量 ,实际上还是操作 this.elementData
        	r 是为了遍历对象 和判断是否遍历成功
        	遍历之后 根据 complement 判断是否包含 , 所以这里传入的是false 将不包含的留下
        	同理,也可以传入true 将包含的留下
        	w 是留下的新数组长度
        	modCount 修改次数为 剔除元素个数
        **/
    }


  	/**
  		移除全部 函数
     * Removes all of the elements from this list.  The list will
     * be empty after this call returns.
     */
    public void clear() {
        // 修改次数加一
        modCount++;
		// 将数组 全部置null
        // 这里只是数组不持有对象的引用 并改变实际对象的值
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;
		// 大小为 0
        size = 0;
    }

	

ArrayList 查找元素

public E get(int index) ;

public int indexOf(Object o) ;

public int lastIndexOf(Object o) ;

public boolean contains(Object o);

public boolean containsAll(Collection<?> c) ;

public Iterator iterator() ;

 /**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        // 越界检测
        rangeCheck(index);
		// 返回元素  看到这里就会发现 后面的函数在之前基本上都讲过了
        return elementData(index);
    }	

	/**
	这个函数上面也是讲过的 
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }


  /**
     * Returns the index of the last occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the highest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
    public int lastIndexOf(Object o) {
        if (o == null) {
            // 与上面函数不同的是,这个是从后往前检索
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * Returns <tt>true</tt> if this list contains the specified element.
     * More formally, returns <tt>true</tt> if and only if this list contains
     * at least one element <tt>e</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param o element whose presence in this list is to be tested
     * @return <tt>true</tt> if this list contains the specified element
     */
    public boolean contains(Object o) {
        // 还是调用上面的函数 如果大于等于0  就找到了
        // 如果-1 就没有找到就是false
        return indexOf(o) >= 0;
    }


    /**
     * {@inheritDoc}
     *
     * <p>This implementation iterates over the specified collection,
     * checking each element returned by the iterator in turn to see
     * if it's contained in this collection.  If all elements are so
     * contained <tt>true</tt> is returned, otherwise <tt>false</tt>.
     *
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @see #contains(Object)
     */
    public boolean containsAll(Collection<?> c) {
        // 直接循环集合c 
        for (Object e : c)
            // 判断有不包含 直接返回false
            if (!contains(e))
                return false;
        // 返回全部包含
        return true;
    }
 

 * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param o element whose presence in this list is to be tested
     * @return <tt>true</tt> if this list contains the specified element
     */
    public boolean contains(Object o) {
        // 还是调用上面的函数 如果大于等于0  就找到了
        // 如果-1 就没有找到就是false
        return indexOf(o) >= 0;
    }


    /**
     * {@inheritDoc}
     *
     * <p>This implementation iterates over the specified collection,
     * checking each element returned by the iterator in turn to see
     * if it's contained in this collection.  If all elements are so
     * contained <tt>true</tt> is returned, otherwise <tt>false</tt>.
     *
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @see #contains(Object)
     */
    public boolean containsAll(Collection<?> c) {
        // 直接循环集合c 
        for (Object e : c)
            // 判断有不包含 直接返回false
            if (!contains(e))
                return false;
        // 返回全部包含
        return true;
    }
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

木秀林

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

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

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

打赏作者

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

抵扣说明:

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

余额充值