Java ArrayList 工作原理及实现

先来一段官方的解释:

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)

ArrayList是一个相对来说比较简单的数据结构,最重要的一点就是它的自动扩容,可以认为就是我们常说的“动态数组”。

来看一段简单的代码:

ArrayList<String> list = new ArrayList<String>();

list.add("语文: 99");

list.add("数学: 98");

list.add("英语: 100");

list.remove(0);

执行完上面的这段代码,结果如下图所示:

add操作就是直接将数组的内容置位,remove操作可以理解为删除index为0的节点,并将后面元素移到0处。

add函数

当我们在ArrayList中增加元素的时候,会使用add函数。他会将元素放到末尾。具体实现如下:

public boolean add(E e) {

   ensureCapacityInternal(size + 1);  // Increments modCount!!

   elementData[size++] = e;

   return true;

}

我们可以看到他的实现其实最核心的内容就是ensureCapacityInternal。这个函数其实就是自动扩容机制的核心。我们依次来看一下他的具体实现:

private void ensureCapacityInternal(int minCapacity) {
   if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
       minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
   }
   ensureExplicitCapacity(minCapacity);
}

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

   // overflow-conscious code
   if (minCapacity - elementData.length > 0)
       grow(minCapacity);
}

private void grow(int minCapacity) {
   // overflow-conscious code

   int oldCapacity = elementData.length;
   // 扩展为原来的1.5倍

   int newCapacity = oldCapacity + (oldCapacity >> 1);
   // 如果扩为1.5倍还不满足需求,直接扩为需求值

   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:
   elementData = Arrays.copyOf(elementData, newCapacity);
}

也就是说,当增加数据的时候,如果ArrayList的大小已经不满足需求时,那么就将数组变为原长度的1.5倍,之后的操作就是把老的数组拷到新的数组里面。

例如,默认的数组大小是10,也就是说当我们add10个元素之后,再进行一次add时,就会发生自动扩容,数组长度由10变为了15具体情况如下所示:

 set函数和get函数

Array的put和get函数就比较简单了,先做index检查,然后执行赋值或访问操作:

public E set(int index, E element) {
   rangeCheck(index);
   E oldValue = elementData(index);
   elementData[index] = element;
   return oldValue;
}

public E get(int index) {
   rangeCheck(index);
   return elementData(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);
   // 把最后的置null
   elementData[--size] = null; // clear to let GC do its work
   return oldValue;

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值