Arralist源码分析

14人阅读 评论(0) 收藏 举报
  • 在看源码之前先看两个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()方法内部并没有减少数组空间 ,而是清空指向而已,但是数组空间还是在的。

查看评论

ArraList源码分析

一、对于ArrayList需要掌握的七点内容 ArrayList的创建:即构造器往ArrayList中添加对象:即add(E)方法获取ArrayList中的单个对象:即get(int index...
  • cwl_0514
  • cwl_0514
  • 2017-10-11 10:38:47
  • 85

ArraList的用法

Java中ArrayList类的用法 1、什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增...
  • u010056403
  • u010056403
  • 2014-07-15 20:08:30
  • 463

ArraList,LinkList,List,Vector的区别

API 在由Ken Arnold等编著的《Java Programming Language》(Addison-Wesley, June 2000)一书中有这样的描述,Vector类似于ArrayL...
  • cs_fei
  • cs_fei
  • 2013-08-04 17:00:28
  • 1047

ArraList和linkedList的区别及优缺点以及Comparable与Comparator的区别

1.ArraList和linkedList的区别及优缺点      1).ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表的数据结构      2).对于随机访问g...
  • mingyuanjava
  • mingyuanjava
  • 2013-10-11 22:46:24
  • 924

ArrayList源码

  • 2010年07月22日 21:39
  • 95KB
  • 下载

nginx源码分析文档

  • 2009年07月03日 14:29
  • 12KB
  • 下载

Lua源码分析

  • 2018年01月12日 23:08
  • 2.19MB
  • 下载

java jdk1.7版本的ArrayList原理解析

上一篇文章中我们了解了LinkedList集合的底层实现原理,这一篇将研究下ArrayList的实现原理。 同样的通过源码解释,我们可以得到以下信息: (1)、ArrayList是一个长度可变的数...
  • LZJLZJLZJLZJLZJLZJ
  • LZJLZJLZJLZJLZJLZJ
  • 2016-08-23 15:57:06
  • 766

snort源码分析

  • 2008年06月26日 00:15
  • 1.89MB
  • 下载

del.asp源码分析

  • 2018年02月12日 19:05
  • 11KB
  • 下载
    个人资料
    等级:
    访问量: 50万+
    积分: 6944
    排名: 4170