extends AbstractList E > implements List E >, RandomAccess , Cloneable , java.io.Serializable ①、實(shí)現(xiàn) RandomAccess 接口 這是一個(gè)標(biāo)記接口,一般此標(biāo)記接口用于 List 實(shí)現(xiàn),以表明它們支持快速(通常是恒定時(shí)間)的隨機(jī)訪問。該接口的主要目的是允許通用算法改變其行為,以便在應(yīng)用于隨機(jī)或順序訪問列表時(shí)提供良好的性能。 比如在工具類 Collections(這個(gè)工具類后面" />
0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

JDK中java.util.ArrayList 類的介紹

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-10 15:51 ? 次閱讀

1、ArrayList 定義

ArrayList 是一個(gè)用數(shù)組實(shí)現(xiàn)的集合,支持隨機(jī)訪問,元素有序且可以重復(fù)。

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

圖片①、實(shí)現(xiàn) RandomAccess 接口

這是一個(gè)標(biāo)記接口,一般此標(biāo)記接口用于 List 實(shí)現(xiàn),以表明它們支持快速(通常是恒定時(shí)間)的隨機(jī)訪問。該接口的主要目的是允許通用算法改變其行為,以便在應(yīng)用于隨機(jī)或順序訪問列表時(shí)提供良好的性能。

比如在工具類 Collections(這個(gè)工具類后面會(huì)詳細(xì)講解)中,應(yīng)用二分查找方法時(shí)判斷是否實(shí)現(xiàn)了 RandomAccess 接口:

int binarySearch(List< ? extends Comparable< ? super T >> list, T key) {
        if (list instanceof RandomAccess || list.size()

②、實(shí)現(xiàn) Cloneable 接口

這個(gè)類是 java.lang.Cloneable,前面我們講解深拷貝和淺拷貝的原理時(shí),我們介紹了淺拷貝可以通過調(diào)用 Object.clone() 方法來實(shí)現(xiàn),但是調(diào)用該方法的對(duì)象必須要實(shí)現(xiàn) Cloneable 接口,否則會(huì)拋出 CloneNoSupportException異常。

Cloneable 和 RandomAccess 接口一樣也是一個(gè)標(biāo)記接口,接口內(nèi)無任何方法體和常量的聲明,也就是說如果想克隆對(duì)象,必須要實(shí)現(xiàn) Cloneable 接口,表明該類是可以被克隆的。

③、實(shí)現(xiàn) Serializable 接口

這個(gè)沒什么好說的,也是標(biāo)記接口,表示能被序列化。

④、實(shí)現(xiàn) List 接口

這個(gè)接口是 List 類集合的上層接口,定義了實(shí)現(xiàn)該接口的類都必須要實(shí)現(xiàn)的一組方法,如下所示,下面我們會(huì)對(duì)這一系列方法的實(shí)現(xiàn)做詳細(xì)介紹。

圖片

2、字段屬性

//集合的默認(rèn)大小
        private static final int DEFAULT_CAPACITY = 10;
        //空的數(shù)組實(shí)例
        private static final Object[] EMPTY_ELEMENTDATA = {};
        //這也是一個(gè)空的數(shù)組實(shí)例,和EMPTY_ELEMENTDATA空數(shù)組相比是用于了解添加元素時(shí)數(shù)組膨脹多少
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
        //存儲(chǔ) ArrayList集合的元素,集合的長(zhǎng)度即這個(gè)數(shù)組的長(zhǎng)度
        //1、當(dāng) elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 時(shí)將會(huì)清空 ArrayList
        //2、當(dāng)添加第一個(gè)元素時(shí),elementData 長(zhǎng)度會(huì)擴(kuò)展為 DEFAULT_CAPACITY=10
        transient Object[] elementData;
        //表示集合的長(zhǎng)度
        private int size;

3、構(gòu)造函數(shù)

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

此無參構(gòu)造函數(shù)將創(chuàng)建一個(gè) DEFAULTCAPACITY_EMPTY_ELEMENTDATA 聲明的數(shù)組,注意此時(shí)初始容量是0,而不是大家以為的 10。

注意 :根據(jù)默認(rèn)構(gòu)造函數(shù)創(chuàng)建的集合,ArrayList list = new ArrayList();此時(shí)集合長(zhǎng)度是0.

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

初始化集合大小創(chuàng)建 ArrayList 集合。當(dāng)大于0時(shí),給定多少那就創(chuàng)建多大的數(shù)組;當(dāng)?shù)扔?時(shí),創(chuàng)建一個(gè)空數(shù)組;當(dāng)小于0時(shí),拋出異常。

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

這是將已有的集合復(fù)制到 ArrayList 集合中去。

4、添加元素

通過前面的字段屬性和構(gòu)造函數(shù),我們知道 ArrayList 集合是由數(shù)組構(gòu)成的,那么向 ArrayList 中添加元素,也就是向數(shù)組賦值。我們知道一個(gè)數(shù)組的聲明是能確定大小的,而使用 ArrayList 時(shí),好像是能添加任意多個(gè)元素,這就涉及到數(shù)組的擴(kuò)容。

擴(kuò)容的核心方法就是調(diào)用前面我們講過的Arrays.copyOf 方法,創(chuàng)建一個(gè)更大的數(shù)組,然后將原數(shù)組元素拷貝過去即可。下面我們看看具體實(shí)現(xiàn):

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  //添加元素之前,首先要確定集合的大小
        elementData[size++] = e;
        return true;
    }

如上所示,在通過調(diào)用 add 方法添加元素之前,我們要首先調(diào)用 ensureCapacityInternal 方法來確定集合的大小,如果集合滿了,則要進(jìn)行擴(kuò)容操作。

private void ensureCapacityInternal(int minCapacity) {//這里的minCapacity 是集合當(dāng)前大小+1
        //elementData 是實(shí)際用來存儲(chǔ)元素的數(shù)組,注意數(shù)組的大小和集合的大小不是相等的,前面的size是指集合大小
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果數(shù)組為空,則從size+1的值和默認(rèn)值10中取最大的
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;//不為空,則返回size+1
    }
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

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

在 ensureExplicitCapacity 方法中,首先對(duì)修改次數(shù)modCount加一,這里的modCount給ArrayList的迭代器使用的,在并發(fā)操作被修改時(shí),提供快速失敗行為(保證modCount在迭代期間不變,否則拋出ConcurrentModificationException異常,可以查看源碼865行),接著判斷minCapacity是否大于當(dāng)前ArrayList內(nèi)部數(shù)組長(zhǎng)度,大于的話調(diào)用grow方法對(duì)內(nèi)部數(shù)組elementData擴(kuò)容,grow方法代碼如下:

private void grow(int minCapacity) {
        int oldCapacity = elementData.length;//得到原始數(shù)組的長(zhǎng)度
        int newCapacity = oldCapacity + (oldCapacity > > 1);//新數(shù)組的長(zhǎng)度等于原數(shù)組長(zhǎng)度的1.5倍
        if (newCapacity - minCapacity < 0)//當(dāng)新數(shù)組長(zhǎng)度仍然比minCapacity小,則為保證最小長(zhǎng)度,新數(shù)組等于minCapacity
            newCapacity = minCapacity;
        //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 = 2147483639
        if (newCapacity - MAX_ARRAY_SIZE > 0)//當(dāng)?shù)玫降男聰?shù)組長(zhǎng)度比 MAX_ARRAY_SIZE 大時(shí),調(diào)用 hugeCapacity 處理大數(shù)組
            newCapacity = hugeCapacity(minCapacity);
        //調(diào)用 Arrays.copyOf 將原數(shù)組拷貝到一個(gè)大小為newCapacity的新數(shù)組(注意是拷貝引用)
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // 
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? //minCapacity > MAX_ARRAY_SIZE,則新數(shù)組大小為Integer.MAX_VALUE
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

對(duì)于 ArrayList 集合添加元素,我們總結(jié)一下:

①、當(dāng)通過 ArrayList() 構(gòu)造一個(gè)空集合,初始長(zhǎng)度是為0的,第 1 次添加元素,會(huì)創(chuàng)建一個(gè)長(zhǎng)度為10的數(shù)組,并將該元素賦值到數(shù)組的第一個(gè)位置。

②、第 2 次添加元素,集合不為空,而且由于集合的長(zhǎng)度size+1是小于數(shù)組的長(zhǎng)度10,所以直接添加元素到數(shù)組的第二個(gè)位置,不用擴(kuò)容。

③、第 11 次添加元素,此時(shí) size+1 = 11,而數(shù)組長(zhǎng)度是10,這時(shí)候創(chuàng)建一個(gè)長(zhǎng)度為10+10*0.5 = 15 的數(shù)組(擴(kuò)容1.5倍),然后將原數(shù)組元素引用拷貝到新數(shù)組。并將第 11 次添加的元素賦值到新數(shù)組下標(biāo)為10的位置。

④、第 Integer.MAX_VALUE - 8 = 2147483639,然后 2147483639%1.5=1431655759(這個(gè)數(shù)是要進(jìn)行擴(kuò)容) 次添加元素,為了防止溢出,此時(shí)會(huì)直接創(chuàng)建一個(gè) 1431655759+1 大小的數(shù)組,這樣一直,每次添加一個(gè)元素,都只擴(kuò)大一個(gè)范圍。

⑤、第 Integer.MAX_VALUE - 7 次添加元素時(shí),創(chuàng)建一個(gè)大小為 Integer.MAX_VALUE 的數(shù)組,在進(jìn)行元素添加。

⑥、第 Integer.MAX_VALUE + 1 次添加元素時(shí),拋出 OutOfMemoryError 異常。

注意:能向集合中添加 null 的,因?yàn)閿?shù)組可以有 null 值存在。

Object[] obj = {null,1};

ArrayList list = new ArrayList();
list.add(null);
list.add(1);
System.out.println(list.size());//2

5、刪除元素

①、根據(jù)索引刪除元素

public E remove(int index) {
        rangeCheck(index);//判斷給定索引的范圍,超過集合大小則拋出異常

        modCount++;
        E oldValue = elementData(index);//得到索引處的刪除元素

        int numMoved = size - index - 1;
        if (numMoved > 0)//size-index-1 > 0 表示 0<= index < (size-1),即索引不是最后一個(gè)元素
            //通過 System.arraycopy()將數(shù)組elementData 的下標(biāo)index+1之后長(zhǎng)度為 numMoved的元素拷貝到從index開始的位置
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; //將數(shù)組最后一個(gè)元素置為 null,便于垃圾回收

        return oldValue;
    }

remove(int index) 方法表示刪除索引index處的元素,首先通過 rangeCheck(index) 方法判斷給定索引的范圍,超過集合大小則拋出異常;接著通過 System.arraycopy 方法對(duì)數(shù)組進(jìn)行自身拷貝。關(guān)于這個(gè)方法的用法可以參考這篇博客。

②、直接刪除指定元素

public boolean remove(Object o) {
        if (o == null) {//如果刪除的元素為null
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {//不為null,通過equals方法判斷對(duì)象是否相等
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }


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

remove(Object o)方法是刪除第一次出現(xiàn)的該元素。然后通過System.arraycopy進(jìn)行數(shù)組自身拷貝。

6、修改元素

通過調(diào)用 set(int index, E element) 方法在指定索引 index 處的元素替換為 element。并返回原數(shù)組的元素。

public E set(int index, E element) {
        rangeCheck(index);//判斷索引合法性

        E oldValue = elementData(index);//獲得原數(shù)組指定索引的元素
        elementData[index] = element;//將指定所引處的元素替換為 element
        return oldValue;//返回原數(shù)組索引元素
    }

通過調(diào)用 rangeCheck(index) 來檢查索引合法性。

private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

當(dāng)索引為負(fù)數(shù)時(shí),會(huì)拋出 java.lang.ArrayIndexOutOfBoundsException 異常。當(dāng)索引大于集合長(zhǎng)度時(shí),會(huì)拋出 IndexOutOfBoundsException 異常。

7、查找元素

①、根據(jù)索引查找元素

public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

同理,首先還是判斷給定索引的合理性,然后直接返回處于該下標(biāo)位置的數(shù)組元素。

②、根據(jù)元素查找索引

public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

注意 :indexOf(Object o) 方法是返回第一次出現(xiàn)該元素的下標(biāo),如果沒有則返回 -1。

還有 lastIndexOf(Object o) 方法是返回最后一次出現(xiàn)該元素的下標(biāo)。

8、遍歷集合

①、普通 for 循環(huán)遍歷 前面我們介紹查找元素時(shí),知道可以通過get(int index)方法,根據(jù)索引查找元素,那么遍歷同理:

ArrayList list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
for(int i = 0 ; i < list.size() ; i++){
    System.out.print(list.get(i)+" ");
}

②、迭代器 iterator 先看看具體用法:

ArrayList< String > list = new ArrayList<  >();
list.add("a");
list.add("b");
list.add("c");
Iterator< String > it = list.iterator();
while(it.hasNext()){
    String str = it.next();
    System.out.print(str+" ");
}

在介紹 ArrayList 時(shí),我們知道該類實(shí)現(xiàn)了 List 接口,而 List 接口又繼承了 Collection 接口,Collection 接口又繼承了 Iterable 接口,該接口有個(gè) Iteratoriterator() 方法,能獲取 Iterator 對(duì)象,能用該對(duì)象進(jìn)行集合遍歷,為什么能用該對(duì)象進(jìn)行集合遍歷?我們?cè)倏纯?ArrayList 類中的該方法實(shí)現(xiàn):

public Iterator< E > iterator() {
         return new Itr();
     }

該方法是返回一個(gè) Itr 對(duì)象,這個(gè)類是 ArrayList 的內(nèi)部類。

private class Itr implements Iterator< E > {
        int cursor;       //游標(biāo), 下一個(gè)要返回的元素的索引
        int lastRet = -1; // 返回最后一個(gè)元素的索引; 如果沒有這樣的話返回-1.
        int expectedModCount = modCount;

        //通過 cursor != size 判斷是否還有下一個(gè)元素
        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();//迭代器進(jìn)行元素迭代時(shí)同時(shí)進(jìn)行增加和刪除操作,會(huì)拋出異常
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;//游標(biāo)向后移動(dòng)一位
            return (E) elementData[lastRet = i];//返回索引為i處的元素,并將 lastRet賦值為i
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);//調(diào)用ArrayList的remove方法刪除元素
                cursor = lastRet;//游標(biāo)指向刪除元素的位置,本來是lastRet+1的,這里刪除一個(gè)元素,然后游標(biāo)就不變了
                lastRet = -1;//lastRet恢復(fù)默認(rèn)值-1
                expectedModCount = modCount;//expectedModCount值和modCount同步,因?yàn)檫M(jìn)行add和remove操作,modCount會(huì)加1
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer< ? super E > consumer) {//便于進(jìn)行forEach循環(huán)
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        //前面在新增元素add() 和 刪除元素 remove() 時(shí),我們可以看到 modCount++。修改set() 是沒有的
        //也就是說不能在迭代器進(jìn)行元素迭代時(shí)進(jìn)行增加和刪除操作,否則拋出異常
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

注意在進(jìn)行 next() 方法調(diào)用的時(shí)候,會(huì)進(jìn)行 checkForComodification() 調(diào)用,該方法表示迭代器進(jìn)行元素迭代時(shí),如果同時(shí)進(jìn)行增加和刪除操作,會(huì)拋出 ConcurrentModificationException 異常。比如:

ArrayList< String > list = new ArrayList<  >();
list.add("a");
list.add("b");
list.add("c");
Iterator< String > it = list.iterator();
while(it.hasNext()){
    String str = it.next();
    System.out.print(str+" ");
    list.remove(str);//集合遍歷時(shí)進(jìn)行刪除或者新增操作,都會(huì)拋出 ConcurrentModificationException 異常
    //list.add(str);
    list.set(0, str);//修改操作不會(huì)造成異常
}

圖片 解決辦法是不調(diào)用 ArrayList.remove() 方法,轉(zhuǎn)而調(diào)用 迭代器的 remove() 方法:

Iterator< String > it = list.iterator();
while(it.hasNext()){
    String str = it.next();
    System.out.print(str+" ");
    //list.remove(str);//集合遍歷時(shí)進(jìn)行刪除或者新增操作,都會(huì)拋出 ConcurrentModificationException 異常
    it.remove();
}

注意 :迭代器只能向后遍歷,不能向前遍歷,能夠刪除元素,但是不能新增元素。

③、迭代器的變種 forEach

ArrayList< String > list = new ArrayList<  >();
list.add("a");
list.add("b");
list.add("c");
for(String str : list){
    System.out.print(str + " ");
}

這種語法可以看成是 JDK 的一種語法糖,通過反編譯 class 文件,我們可以看到生成的 java 文件,其具體實(shí)現(xiàn)還是通過調(diào)用 Iterator 迭代器進(jìn)行遍歷的。如下:

ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        String str;
        for (Iterator iterator1 = list.iterator(); iterator1.hasNext(); System.out.print((new StringBuilder(String.valueOf(str))).append(" ").toString()))
            str = (String)iterator1.next();

④、迭代器 ListIterator 還是先看看具體用法:

ArrayList< String > list = new ArrayList<  >();
list.add("a");
list.add("b");
list.add("c");
ListIterator< String > listIt = list.listIterator();

//向后遍歷
while(listIt.hasNext()){
    System.out.print(listIt.next()+" ");//a b c
}

//向后前遍歷,此時(shí)由于上面進(jìn)行了向后遍歷,游標(biāo)已經(jīng)指向了最后一個(gè)元素,所以此處向前遍歷能有值
while(listIt.hasPrevious()){
    System.out.print(listIt.previous()+" ");//c b a
}

還能一邊遍歷,一邊進(jìn)行新增或者刪除操作:

ArrayList< String > list = new ArrayList<  >();
list.add("a");
list.add("b");
list.add("c");
ListIterator< String > listIt = list.listIterator();

//向后遍歷
while(listIt.hasNext()){
    System.out.print(listIt.next()+" ");//a b c
    listIt.add("1");//在每一個(gè)元素后面增加一個(gè)元素 "1"
}

//向后前遍歷,此時(shí)由于上面進(jìn)行了向后遍歷,游標(biāo)已經(jīng)指向了最后一個(gè)元素,所以此處向前遍歷能有值
while(listIt.hasPrevious()){
    System.out.print(listIt.previous()+" ");//1 c 1 b 1 a 
}

也就是說相比于 Iterator 迭代器,這里的 ListIterator 多出了能向前迭代,以及能夠新增元素。下面我們看看具體實(shí)現(xiàn):

對(duì)于 Iterator 迭代器,我們查看 JDK 源碼,發(fā)現(xiàn)還有 ListIterator 接口繼承了 Iterator:

public interface ListIteratorextends Iterator

該接口有如下方法:

圖片 我們看在 ArrayList 類中,有如下方法可以獲得 ListIterator 接口:

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

這里的 ListItr 也是一個(gè)內(nèi)部類。

//注意 內(nèi)部類 ListItr 繼承了另一個(gè)內(nèi)部類 Itr
    private class ListItr extends Itr implements ListIterator< E > {
        ListItr(int index) {//構(gòu)造函數(shù),進(jìn)行游標(biāo)初始化
            super();
            cursor = index;
        }

        public boolean hasPrevious() {//判斷是否有上一個(gè)元素
            return cursor != 0;
        }

        public int nextIndex() {//返回下一個(gè)元素的索引
            return cursor;
        }

        public int previousIndex() {//返回上一個(gè)元素的索引
            return cursor - 1;
        }

        //該方法獲取當(dāng)前索引的上一個(gè)元素
        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();//迭代器進(jìn)行元素迭代時(shí)同時(shí)進(jìn)行增加和刪除操作,會(huì)拋出異常
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;//游標(biāo)指向上一個(gè)元素
            return (E) elementData[lastRet = i];//返回上一個(gè)元素的值
        }

        
        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        //相比于迭代器 Iterator ,這里多了一個(gè)新增操作
        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

9、SubList

在 ArrayList 中有這樣一個(gè)方法:

public List< E > subList(int fromIndex, int toIndex) {
         subListRangeCheck(fromIndex, toIndex, size);
         return new SubList(this, 0, fromIndex, toIndex);
     }

作用是返回從 fromIndex(包括) 開始的下標(biāo),到 toIndex(不包括) 結(jié)束的下標(biāo)之間的元素視圖。如下:

ArrayList< String > list = new ArrayList<  >();
list.add("a");
list.add("b");
list.add("c");

List< String > subList = list.subList(0, 1);
for(String str : subList){
    System.out.print(str + " ");//a
}

這里出現(xiàn)了 SubList 類,這也是 ArrayList 中的一個(gè)內(nèi)部類。

注意:返回的是原集合的視圖,也就是說,如果對(duì) subList 出來的集合進(jìn)行修改或新增操作,那么原始集合也會(huì)發(fā)生同樣的操作。

ArrayList< String > list = new ArrayList<  >();
list.add("a");
list.add("b");
list.add("c");

List< String > subList = list.subList(0, 1);
for(String str : subList){
    System.out.print(str + " ");//a
}
subList.add("d");
System.out.println(subList.size());//2
System.out.println(list.size());//4,原始集合長(zhǎng)度也增加了

想要獨(dú)立出來一個(gè)集合,解決辦法如下:

ListsubList = new ArrayList<>(list.subList(0, 1));

10、size()

public int size() {
        return size;
    }

注意:返回集合的長(zhǎng)度,而不是數(shù)組的長(zhǎng)度,這里的 size 就是定義的全局變量。

11、isEmpty()

public boolean isEmpty() {
         return size == 0;
     }

返回 size == 0 的結(jié)果。

12、trimToSize()

public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }

該方法用于回收多余的內(nèi)存。也就是說一旦我們確定集合不在添加多余的元素之后,調(diào)用 trimToSize() 方法會(huì)將實(shí)現(xiàn)集合的數(shù)組大小剛好調(diào)整為集合元素的大小。

注意 :該方法會(huì)花時(shí)間來復(fù)制數(shù)組元素,所以應(yīng)該在確定不會(huì)添加元素之后在調(diào)用。

13、小結(jié)

好了,這就是JDK中java.util.ArrayList 類的介紹。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8605

    瀏覽量

    151197
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2967

    瀏覽量

    104764
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    417

    瀏覽量

    25949
  • JDK
    JDK
    +關(guān)注

    關(guān)注

    0

    文章

    81

    瀏覽量

    16597
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    OpenHarmony語言基礎(chǔ)庫【@ohos.util.ArrayList (線性容器ArrayList)】

    ArrayList是一種線性數(shù)據(jù)結(jié)構(gòu),底層基于數(shù)組實(shí)現(xiàn)。ArrayList會(huì)根據(jù)實(shí)際需要?jiǎng)討B(tài)調(diào)整容量,每次擴(kuò)容增加50%。
    的頭像 發(fā)表于 04-25 18:48 ?628次閱讀
    OpenHarmony語言基礎(chǔ)<b class='flag-5'>類</b>庫【@ohos.<b class='flag-5'>util.ArrayList</b> (線性容器<b class='flag-5'>ArrayList</b>)】

    Java對(duì)List集合的常用操作詳解 北京java軟件開發(fā)

    處理,我們可以采用subList方法進(jìn)行實(shí)現(xiàn),具體用法可參看以下案例:import java.util.ArrayList;import java.util.List;public class
    發(fā)表于 01-19 17:28

    Java利用hanlp完成語句相似度分析的案例詳解

    ;import java.util.ArrayList;import java.util.Calendar;import java.util.Collections;import
    發(fā)表于 02-23 10:27

    樹莓派如何安裝Java JDK

    。Oracle Java 具有其他一些商業(yè)功能,并且許可僅允許非商業(yè)用途。下面介紹如何在樹莓派的 Raspbian OS 上安裝Java(OpenJDK)?! ∵\(yùn)行以下命令安裝最新的 JDK
    發(fā)表于 02-02 16:37

    Android平臺(tái)藍(lán)牙串口驅(qū)動(dòng)代碼分享

    java.util.ArrayList;import java.util.UUID;import android.app.Activity;import android.bluetooth.BluetoothAdapter;import android.bluetoot
    發(fā)表于 03-02 06:44

    【學(xué)習(xí)打卡】OpenHarmony的ArrayList介紹

    在底層的集合允許我們?cè)贚ist 接口的幫助下插入和刪除元素。List 接口是一個(gè)有序的對(duì)象集合,允許存儲(chǔ)重復(fù)值。 ArrayList是OpenHarmony實(shí)現(xiàn)List接口特性的,具有結(jié)構(gòu)
    發(fā)表于 07-27 21:51

    java jdk6.0官方下載

    java jdk6.0下載如何件: java jdk6.0安裝步驟: 第一步 JDK1.6的安裝步驟 第一步雙擊安裝文件
    發(fā)表于 10-17 11:47 ?155次下載
    <b class='flag-5'>java</b> <b class='flag-5'>jdk</b>6.0官方下載

    java基礎(chǔ)——java.util.ConcurrentModificationException

    本文檔內(nèi)容介紹java基礎(chǔ)java.util.ConcurrentModificationException,供參考
    發(fā)表于 03-13 11:31 ?2次下載

    JavaArrays是什么 Arrays常用方法

    了解Arrays的概念 **A****rrays** 位于java.util包下,Arrays是一個(gè)操作數(shù)組的工具。 Arrays常用方法 Arrays.fill:
    的頭像 發(fā)表于 02-17 15:11 ?1050次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>中</b>Arrays<b class='flag-5'>類</b>是什么 Arrays常用方法

    JDKjava.util.HashSet 介紹

    JDK1.8 ,HashMap 是由 數(shù)組+鏈表+紅黑樹構(gòu)成,相對(duì)于早期版本的 JDK HashMap 實(shí)現(xiàn),新增了紅黑樹作為底層數(shù)據(jù)結(jié)構(gòu),在數(shù)據(jù)量較大且哈希碰撞較多時(shí),能夠極大的增加檢索
    的頭像 發(fā)表于 10-09 10:50 ?600次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java.util</b>.HashSet <b class='flag-5'>類</b>的<b class='flag-5'>介紹</b>

    JDKjava.util.TreeMap 介紹

    本篇文章給大家介紹基于樹實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)——TreeMap 1、TreeMap 定義 聽名字就知道,TreeMap 是由Tree 和 Map 集合有關(guān)的,沒錯(cuò),TreeMap 是由紅黑樹實(shí)現(xiàn)的有序
    的頭像 發(fā)表于 10-10 11:45 ?573次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java.util</b>.TreeMap <b class='flag-5'>類</b>的<b class='flag-5'>介紹</b>

    JDKjava.lang.Arrays 的源碼解析

    日常開發(fā),我們會(huì)使用各種工具,利用封裝好的輪子,能讓我們的開發(fā)事半功倍。但是在JDK,有一個(gè)特別的工具——
    的頭像 發(fā)表于 10-11 15:31 ?616次閱讀
    <b class='flag-5'>JDK</b><b class='flag-5'>中</b><b class='flag-5'>java</b>.lang.Arrays <b class='flag-5'>類</b>的源碼解析

    javautil包下有哪些

    Javautil包下,包含了許多,用于提供各種常見的實(shí)用工具和數(shù)據(jù)結(jié)構(gòu)。以下是一些常見的ArrayList:動(dòng)態(tài)數(shù)組,可以根據(jù)需
    的頭像 發(fā)表于 11-22 15:04 ?1139次閱讀

    weblogic修改jdk路徑

    )路徑的情況。本文將詳細(xì)介紹如何在WebLogic修改JDK路徑。 一、背景介紹 Java Development Kit(
    的頭像 發(fā)表于 12-05 14:46 ?1317次閱讀

    鴻蒙語言基礎(chǔ)庫:ohos.util.ArrayList 線性容器ArrayList

    ArrayList是一種線性數(shù)據(jù)結(jié)構(gòu),底層基于數(shù)組實(shí)現(xiàn)。ArrayList會(huì)根據(jù)實(shí)際需要?jiǎng)討B(tài)調(diào)整容量,每次擴(kuò)容增加50%。
    的頭像 發(fā)表于 07-10 09:37 ?251次閱讀
    鴻蒙語言基礎(chǔ)<b class='flag-5'>類</b>庫:ohos.<b class='flag-5'>util.ArrayList</b> 線性容器<b class='flag-5'>ArrayList</b>