【面試大綱】Java集合-ArrayList

List

首先說(shuō)一下list的一些特點(diǎn):list中的元素是有序并且有重復(fù)的!
以下內(nèi)容請(qǐng)結(jié)合源碼一起食用效果更佳!

ArrayList

底層是什么?

ArrayList的底層是數(shù)組。

初始化參數(shù)有哪些?

  • 默認(rèn)容量是10;
  • 當(dāng)調(diào)用 new ArrayList(),即調(diào)用空的構(gòu)造函數(shù)的時(shí)候是默認(rèn)初始化一個(gè)空數(shù)組。然后往數(shù)組添加元素也即調(diào)用add(E)或add(int, E)方法的時(shí)候才初始化數(shù)組容量為默認(rèn)值10;
  • 當(dāng)調(diào)用 new ArrayList(int initialCapacity),即調(diào)用指定數(shù)組容量的構(gòu)造函數(shù)的時(shí)候是默認(rèn)初始化一個(gè)指定大小的數(shù)組;

擴(kuò)容機(jī)制是怎樣的?

  • 當(dāng)添加新的元素的時(shí)候,如果size+1大于當(dāng)前數(shù)組的容量,默認(rèn)擴(kuò)容為原數(shù)組容量的1.5倍,這個(gè)1.5倍的說(shuō)法不是很?chē)?yán)謹(jǐn),源碼中是 int newCapacity = oldCapacity + (oldCapacity >> 1);,也即原容量+原容量右移一位,可以理解為原容量+原容量/2(即對(duì)2取整的結(jié)果)。

是否線程安全?

ArrayList是非線程安全的!為什么?

  • 當(dāng)不會(huì)觸發(fā)擴(kuò)容的時(shí)候,新元素添加到數(shù)組中的操作是elementData[size++] = e;,這里size++操作就不是線程安全的,因?yàn)樗皇且粋€(gè)原子操作,多線程情況下很容易出現(xiàn)并發(fā)的問(wèn)題!
  • 當(dāng)觸發(fā)擴(kuò)容的時(shí)候,可能會(huì)出現(xiàn)數(shù)組元素丟失的情況,具體是怎么個(gè)丟失法呢?假設(shè)數(shù)組容量是10,現(xiàn)在有兩個(gè)線程同時(shí)執(zhí)行到grow()方法,在最后一步執(zhí)行數(shù)組拷貝以及重復(fù)賦值時(shí),兩個(gè)線程都執(zhí)行了數(shù)組的拷貝,然后A線程先賦值elementData = Arrays.copyOf(elementData, newCapacity);,接著完成了add方法,此時(shí)數(shù)組elementData[10]這個(gè)位置就添加量新的元素,然后B線程再進(jìn)行數(shù)組的賦值,此時(shí)就會(huì)將A線程添加的元素值給覆蓋掉的情況!這個(gè)過(guò)程好好想想還是可以理解的!

拓展: 如果想要使用線程安全的ArrayList有沒(méi)有呢?
可選方案有:Vector、Collections.synchronizedList()、CopyOnWriteArrayList
小妙招:如果能確定ArrayList的初始容量,最好是使用new ArrayList(int initialCapacity)這個(gè)構(gòu)造函數(shù),避免數(shù)組擴(kuò)容帶來(lái)額外的影響。

使用場(chǎng)景有哪些?

ArrayList的一個(gè)特性就是它的底層是基于數(shù)組的,數(shù)組是一種線性數(shù)據(jù)結(jié)構(gòu),在內(nèi)存中的存儲(chǔ)空間是連續(xù)的。

  • 查詢的效率高,因?yàn)榭臻g連續(xù),支持通過(guò)下標(biāo)的隨機(jī)訪問(wèn);
  • 增刪改的效率可能不是很好,因?yàn)橐匦驴截悢?shù)組,當(dāng)數(shù)組的元素特別多的時(shí)候,這個(gè)效率可想而知!

所以說(shuō),對(duì)于只是隨機(jī)訪問(wèn)的,使用ArrayList是個(gè)不錯(cuò)的選擇,效率高還安全!如果要執(zhí)行一些增刪改的操作,可以考慮使用LinkedList!
下一篇就說(shuō)一下LinkedList!

彩蛋
多次執(zhí)行下面的代碼,看看有什么發(fā)現(xiàn)?

public class ArrayListUnsafeTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(10);
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容