集合ArrayList原理刨解JDK1.8(1)

介紹
List表示有順序的集合,implements Cloneable擴展了基本方法,
RandomAccess 標記接口,表示此類能隨機訪問,類似數組特性,
對象是連續存儲的,根據索引直接定位到元素,訪問效率高,LinkedList不能隨機訪問。繼承AbstractList抽象類可以實現一些默認方法。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

數據特性
內部是動態數組,根據索引訪問效率高。插入和刪除元素的效率低,因爲需要移動元素,線程不安全。

1.基本使用方法介紹

public boolean add (E e)//添加元素到末尾
public boolean isempty ()//判斷是否爲空
public int size () //獲取長度
public E get ( int index)//訪問指定位置的元素
public int indexof (object o)//查找元素, 如果找到, 返回索引位置, 否則返回 - 1
public int astindexof (Object o)//從後往前找
public boolean contains (Object o)//是否包含指定元素,依據是equa1s方法的返回值
public E remove ( int index)//刪除指定位置的元素,返回值爲被刪對象
//刪除指定對象,只刪除第一個相同的對象,返回值表示是否刪除了元素
//如果。爲nu11, 則刪除值爲nu11的元素
public boolean remove (Object o)
public void clear ()//刪除所有元素
//在指定位置插入元素, index爲0表示插入最前面, index爲 Arraylist的長度表示插到最後面
public void add ( int index, E element)
public E set ( int index, E element)//修改指定位置的元素內容

2.基本原理

內部一個elementData數組,一般有一些預留的空間,有一個整數size記錄實際元素的個數,
各種public方法內部是基本是操作這個數組和元素個數,隨着elementData實際元素個數的增多重新分配,size記錄元素個數

transient Object[] elementData;
private int size;

add()添加容量10的原理,首先調用ensureCapacityInternal確保數組容量是否夠,判斷數組是不是空,是空,首先分配DEFAULT_CAPACITY默認值10容量,不是空數組調用ensureExplicitCapacitygrow方法擴容。

//首先調用ensureCapacityInternal確保數組容量是否夠
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}

private void ensureCapacityInternal(int minCapacity) {
//判斷數組是不是空,是空,首先分配DEFAULT_CAPACITY默認值10容量,
// 不是空調用ensureExplicitCapacity,grow方法擴容。
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
//表示增加修改次數,
modCount++;

if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

private void grow(int minCapacity) {
//原數組長度
int oldCapacity = elementData.length;
//右移一位相當於除以2,所以newCapacity相當於oldCapacity的1.5倍,10+5
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果擴展了1.5倍小於minCapacity增加容量,就擴展minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
}

3.集合遍歷使用
foreach的使用,編譯器會轉換成Iterator 迭代器的使用

//foreach背後實現,編譯器會轉換成迭代器接口
for (Integer integer : list) {
System.out.println(integer);
}

//獲取new Itr();實現類對象
Iterator<Integer> iterator = list.iterator();
//判斷是否還有元素未訪問,next返回下一個元素
while (iterator.hasNext()){
System.out.println(iterator.next());
}

ListIterator接口擴展了Integer接口

   public ListIterator<E> listIterator(int index){
           return new ListItr(index);
}
   public ListIterator<E> listIterator(){
           return new ListItr(index);
}

listItr對象,增加一些方法、向前遍歷、添加元素等方法

 private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) 
        public boolean hasPrevious() 
        public int nextIndex()
        public int previousIndex()
        public E previous()
        public void set(E e)
        public void add(E e)
    }

在迭代會報錯,例如在遍歷的時候調用容器刪除的方法。

      ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(1);
        for (Integer integer : list) {
            list.remove(integer);
        }

發生併發修改異常,這是因爲在迭代器內部維護索引位置信息,在迭代的過程中是不能讓list容器發生變化,否則索引就失效了。
Exception in thread “main” java.util.ConcurrentModificationException

如果要避免這種異常,使用迭代器自己的remove刪除方法

List<Integer> list = new ArrayList<Integer>();
        list.add(22);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            if (iterator.next() <=100){
                iterator.remove();
            }

下一篇迭代器原理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章