zoukankan      html  css  js  c++  java
  • java源码研究--ArrayList实现

    java.util.ArrayList是十分常用的容器之一,本文针对其常用方法,对其进行简单的研究。
    ArrayList常见方法如下,主要还是增删改查:

    首先,看一下ArrayList中如何保存数据的:

    transient Object[] elementData;

    所以,所有的数据都是保存在数组里的。当然,数组都有个大小:

    若ArrayList使用无参构造函数实例化:

    ArrayList<Integer> arrayList = new ArrayList<Integer>();

    那么,内部数组的大小默认就是10:

    1 public ArrayList() {
    2     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //空数组
    3 }
    4 
    5 //刚实例化完,其实数组为空数组,在往arrayList添加数组时才会扩充容量(默认大小为10),扩充过程继续往后看。
    6 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 
    7 private static final int DEFAULT_CAPACITY = 10; //默认最小容量为10

    下面,研究一下add(E element)方法:

    public boolean add(E e) {
    	ensureCapacityInternal(size + 1);  // Increments modCount!!
    	elementData[size++] = e;
    	return true;
    }
    

      其中,ensureCapacityInternal函数用来确保数组大小足够使用(至少为size+1),该函数如下:

     1 private void ensureCapacityInternal(int minCapacity) {
     2     if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //若为空数组(实例化完成后),进入此分支
     3         minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); //minCapacity = Math.max(10, 1);
     4     }
     5 
     6     ensureExplicitCapacity(minCapacity); //ensureExplicitCapacity(10);
     7 }
     8 
     9 private void ensureExplicitCapacity(int minCapacity) {
    10     modCount++;
    11 
    12     // overflow-conscious code
    13     if (minCapacity - elementData.length > 0) //10-0>0
    14         grow(minCapacity); //grow(10); 这就是首次实例化之后的扩充容量了;
    15 }
    16 
    17 private void grow(int minCapacity) {
    18     // overflow-conscious code
    19     int oldCapacity = elementData.length; 
    20     int newCapacity = oldCapacity + (oldCapacity >> 1); //newCapacity 扩充为1.5倍
    21     if (newCapacity - minCapacity < 0)
    22         newCapacity = minCapacity;
    23     if (newCapacity - MAX_ARRAY_SIZE > 0)
    24         newCapacity = hugeCapacity(minCapacity);
    25     // minCapacity is usually close to size, so this is a win:
    26     elementData = Arrays.copyOf(elementData, newCapacity); //首次插数据,将容量扩充为10;之后容量不够时,数组容量按照1.5倍扩充。
    27 }

    可见,在首次插数据时,容量首先将数组容量扩充为10,再执行elementData[size++]=e;
    在数组满了,继续插数据时,会先将容量扩充为1.5倍(10+10*1/2),再继续插数据;
    当数组又满了,再继续扩充为1.5倍(15+15*1/2)......

    因此,在明知数据量很大的情况下,初始化时应该指定合适大小的容量,避免arrayList反复扩充容量

    例如:若数组总容量为8000,可以这样实例化:

    ArrayList<Integer> arrayList = new ArrayList<Integer>(10000);
    

    带参构造函数如下:

    public ArrayList(int initialCapacity) {
    	if (initialCapacity > 0) {
    		this.elementData = new Object[initialCapacity];
    	}
    	.....
    }
    

      

    下面研究一下add(int index, E element)

    public void add(int index, E element) {
    	rangeCheckForAdd(index);
    
    	ensureCapacityInternal(size + 1);  // Increments modCount!!
    	System.arraycopy(elementData, index, elementData, index + 1,
    					 size - index);
    	elementData[index] = element;
    	size++;
    }
    

    这个函数是将新元素插入到数组的指定位置(index),从上面的源码来看,实现过程是先将原先index位置及置换的元素向后移1位,然后再将新元素放在位置index。

      

    继续研究一下remove函数的实现

    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
    
    	return oldValue;
    }
    

    所以,类似的实现原理:将index+1位置及之后的元素先前移动1位,再把最后一个元素清掉。

    了解了ArrayList实现原理,才能更好的选择合适的容器,以及以正确的方式使用,以获取高效率。

    后面将介绍另外一个List接口容器:LinkedList

  • 相关阅读:
    Spring基础知识
    Hibernate基础知识
    Struts2基础知识
    在eclipse里头用checkstyle检查项目出现 File contains tab characters (this is the first instance)原因
    java后台获取cookie里面值得方法
    ckplayer 中的style.swf 中的 style.xml 中的修改方法
    java hql case when 的用法
    Windows下Mongodb安装及配置
    Mongodb中经常出现的错误(汇总)child process failed, exited with error number
    Mac 安装mongodb
  • 原文地址:https://www.cnblogs.com/xinxinBlog/p/9926184.html
Copyright © 2011-2022 走看看