ArrayList源码分析

 ArrayList源码分析

1.构造方法

传一个int型的构造方法:根据传入的参数大于0,创建一个长度为参数的数组并且赋值给elementData这个成员变量,如果参数等于0,赋值为一个空的数组,否则,报错。所以,这也印证了,ArrayList它的底层是数组。


 

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);    }
}

空参构造方法:它执行的操作是给成员变量elementData赋值一个默认的容量,而这个容量是一个private,static,final类型的空数组,即private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {   
 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

传一个集合类型的参数:将传入的集合转为数组赋值给成员变量,然后判断它的长度是否为0,如果不为0,进而判断它是否为Object类型的数组,如果不是的话,给它copyOf()为一个Object类型的数组。否则,给它置空。

public ArrayList(Collection<? extends E> c) {  
 elementData = c.toArray(); 
 if ((size = elementData.length) != 0) {  
     // c.toArray might (incorrectly) not return Object[] (see 6260652)    
     if (elementData.getClass() != Object[].class)   
         elementData = Arrays.copyOf(elementData, size, Object[].class);  
 } else {       
     // replace with empty array.        
     this.elementData = EMPTY_ELEMENTDATA;  
 }
}

2.插入数据:add()方法

在末尾添加元素:首先要判断是否需要扩容,ensureCapacityInternal(size + 1),size+1传入为最小容量,modCount++,调用grow()扩容

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

在指定位置添加元素:首先rangeCheckForAdd(index)判断索引是否超出数组下标,之后检测是否需要扩容,System.arraycopy()除去指定位置,把指定位置的以后的元素向后移一位,将index位置赋新值

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

3.扩容

扩容的时候首先会调用的方法,计算容量,minCapacity即上述的size+1

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

计算最小容量,DEFAULTCAPACITY_EMPTY_ELEMENTDATA(默认容量)是10,

private static int calculateCapacity(Object[] elementData, int minCapacity) {   
 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {    
     return Math.max(DEFAULT_CAPACITY, minCapacity); }   
 return minCapacity;
}

传入最小容量,首先修改+1,minCapacity - elementData.length > 0判断你需要的容量与默认容量的大小,差为负值是不需要扩容的。

private void ensureExplicitCapacity(int minCapacity) {   
modCount++;    // overflow-conscious code  
if (minCapacity - elementData.length > 0)  
grow(minCapacity);
}

数组扩容:首先把数组的长度赋给老的容量,也就是10,然后新的容量newCapacity=老的容量(10)+老的容量右移一位(5),如果新容量-(size+1)为负数,把size+1赋给新容量。如果新容量比数组的最大扩容量都大,会报异常,或者把最大的赋给它。如果都不是,就把新容量拷贝给数组,扩容完成。

private void grow(int minCapacity) {  
// overflow-conscious code    
 int oldCapacity = elementData.length;  
 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:    
 elementData = Arrays.copyOf(elementData, newCapacity);
}

 4.删除

指定位置删除:首先检测是否越界,然后修改+1,

public E remove(int index) {  
rangeCheck(index);    
modCount++; 
 //返回要删除的元素
 E oldValue = elementData(index);
 //将index+1以及之后的元素向前移动一位,覆盖被删除的值
 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;
}

指定元素删除:首先判断是否为空,空的时候直接删除

public boolean remove(Object o) {   
 //判断元素是否为空
 if (o == null) {   
     for (int index = 0; index < size; index++)    
         if (elementData[index] == null) { 
             fastRemove(index);      
             return true;    
         }   
 } else {     
     for (int index = 0; index < size; index++)   
         if (o.equals(elementData[index])) {  
             fastRemove(index);      
             return true;       
         }   
 }  
 //如果没有匹配元素,返回false
 return false;
}

快速删除:不需要检测index,直接删除

private void fastRemove(int index) {   
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
}

5.遍历,删除异常及解决办法

public interface Iterator<E> {   
boolean hasNext();   
 E next();  
 default void remove() {  
     throw new UnsupportedOperationException("remove");  
 }   
 default void forEachRemaining(Consumer<? super E> action) {        Objects.requireNonNull(action);   
while (hasNext())          
    action.accept(next());   
}
}

如果for直接调用remove()方法会报错,因为modCount首先会+1,而expectedModCount是一开始遍历产生的

final void checkForComodification() { 
 if (modCount != expectedModCount)    
     throw new ConcurrentModificationException();
}

但如果用迭代器遍历然后在删除就不会报错,因为expectedModCount = ArrayList.this.modCount;重新赋值了

public void remove() {   
if (lastRet < 0)    
throw new IllegalStateException();   
 checkForComodification();   
 try {       
     SubList.this.remove(lastRet);      
     cursor = lastRet;    
     lastRet = -1;     
     expectedModCount = ArrayList.this.modCount; 
 } catch (IndexOutOfBoundsException ex) {  
     throw new ConcurrentModificationException();  
 }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值