Arralist源码分析

  • 在看源码之前先看两个API:
1. int [] Arrays.copyOf(int[] original, int newLength)
2. System.arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);

两个代码功能相似.解析如下

  • Arrays.copyOf 申请newLength长度的int数组,,然后把original的数值拷贝到新的数组然后返回

如:

   int[] sets = {1, 2};
        //申请int[]类型数组, 长度为4 然后把sets数组的数值拷贝过去 
        //所以数组 ints 为{1,2,0,0} 
        // 申请数组空间没有赋值默认为0
        int[] ints = Arrays.copyOf(sets, 4);
  • System.arraycopy 方法说明:拷贝src数组数值到dest
public static void (Object src,
                             int srcPos,
                             Object dest,
                             int destPos,
                             int length)

src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度。

如:

import java.util.ArrayList;
import java.util.Arrays;

public class Test {

    public static void main(String args[]) {

        int[] sets = {12,2,23};

        int[] ints = {0,0,0,0};
        //sets从第0个位置拷贝到ints,拷贝的数量为3,并且ints[1]位置开始拷贝
        System.arraycopy(sets,0,ints,1,3);
        //输出[0, 12, 2, 23]
        System.out.println(Arrays.toString(ints));
    }
}

源码分析开始

继承关系:
这里写图片描述

案例代码:

import java.util.ArrayList;
import java.util.Arrays;

public class Test {

    public static void main(String args[]) {
        //第8行
        ArrayList<Integer> intSets = new ArrayList<>();
        //第10行
        intSets.add(1);
        //第12行 调用有参数构造方法 ArrayList(int size)
        ArrayList<Integer> intSets2 = new ArrayList<>(2);
        //移除第一个元素
        intSets.remove(0);
    }
}

ArrayList声明的一些属性对象

public class ArrayList{
    //序列化版本号
    private static final long serialVersionUID = 8683452581122892189L;
     //默认的初始化容量 是在add()方法触发后面讲解
    private static final int DEFAULT_CAPACITY = 10;
    //构造方法ArrayList(int size) 当size==0的时候 赋值给elementData引用
    private static final Object[] EMPTY_ELEMENTDATA = {};
    //无惨构造方法构造对象的时候传给elementData引用
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    //保存所有对象的数组 后面讲解    
    transient Object[] elementData; 
    //数组大小
    private int size;
}

注:transient 声明的对象不参与序列化

首先看两个构造方法:

 public ArrayList() {
         //默认指向属性对象数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果初始化容量大于0那么初始化一个和initialCapacity长度相同数组
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果为0那么指向属性数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            //小于0抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

再看看Arrays.add(Object obj) 方法解析对应案例代码第10行intSets.add(1);

 public boolean add(E e) {
         //扩容算法 保证数组空间足够放下对象e 传入放入对象e后的数组大小
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将传入的对象保存在数组中 可见ArrayList是利用数组完成
        elementData[size++] = e;
        return true;
    }

继续 ensureCapacityInternal 方法

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

首先调用calculateCapacity(elementData, minCapacity)方法传入保存对象的数组和加入对象后的长度

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //思想比较简单 如果ArrayList无参数构造方法创建的 
        //elementData保存的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA对象的引用
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //如果加入新的对象后数组长度小于DEFAULT_CAPACITY(默认为10),那么直接返回DEFAULT_CAPACITY,其他反知
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

回头再看看 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));ensureExplicitCapacity方法

 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 如果加入对象后的长度大于原本长度
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

再看看grow()

private void grow(int minCapacity) {
        //旧的数组长度
        int oldCapacity = elementData.length;
        //新的长度为为旧长度的1.5倍,>> 1相当于乘2^1,>>3相当于乘2^3
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果长度还是不够直接 新的长度等于你新加入的后的长度
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
         //如果长度大于ArrayList预定最大长度,长度还需再做一次改变
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            //此方法下文继续讲解 
            newCapacity = hugeCapacity(minCapacity);
        // 创建一个新数组 并且拷贝
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

继续讲解如果长度大于ArrayList预定最大长度,长度还需再做一次改变

 if (newCapacity - MAX_ARRAY_SIZE > 0)
            //此方法下文继续讲解 
            newCapacity = hugeCapacity(minCapacity);

hugeCapacity方法讲解

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) //长度小于0你懂的
            throw new OutOfMemoryError();
           //如果申请长度大于预定长度 那么返回int最大值 否则返回MAX_ARRAY_SIZE
           //MAX_ARRAY_SIZE=Integer.MAX_VALUE -8
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

有人想问MAX_ARRAY_SIZE=Integer.MAX_VALUE -8 意义。为什么不直接给Integer.MAX_VALUE 给人家,还要考虑 -8问题。原因:一些虚拟机在数组中保留一些标头词。尝试分配更大的数组可能会导致OutOfMemoryError: Requested array size exceeds VM limit。

最后看看ArrayList.remove(int index)方法

 public E remove(int index) {
         //检查要删除的元素下标是有效的
        //  rangeCheck方法如下:
        //  if (index >= size)
       //      throw new IndexOutOfBoundsException(outOfBoundsMsg(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

        return oldValue;
    }

remove()方法内部并没有减少数组空间 ,而是清空指向而已,但是数组空间还是在的。

阅读更多
版权声明:范明毅的个人博客,欢迎转载,转载请注明出处 https://blog.csdn.net/qfanmingyiq/article/details/79796458
上一篇搭建shadowsock服务器
下一篇Android逆向之旅
想对作者说点什么? 我来说一句

nginx源码分析文档

2009年07月03日 12KB 下载

没有更多推荐了,返回首页

关闭
关闭