ArrayList源碼解析之初始化

在上一篇《ArrayList源碼解析之架構》

裡面,對ArrayList的整體架構和數組的相關知識做了分享,本節將延續上節知識點,對ArrayList的源碼進行分析,希望對你有所幫助。

1.ArrayList初始化方式

在開始介紹初始化之前,首先需要注意在源碼中有兩個空引用,如下圖:

ArrayList源碼解析之初始化

ArrayList空元素數據

  1. EMPTY_ELEMENTDATA是一個共享空數組實例,當傳入ArrayList構造器的容量為0時,用這個數組表示容器的容量為0。
  2. DEFAULTCAPACITY_EMPTY_ELEMENTDATA也是一個共享的空數組實例,主要是為了區別於EMPTY_ELEMENTDATA,主要作為一個標識位,在擴容時區分默認大小和容量為0,使用默認容量時採取的是“懶加載”,即等到add元素的時候才進行實際容量的分配。

1.1 無參數直接初始化

ArrayList第一種初始化方式是無參數初始化,源碼如下:


ArrayList源碼解析之初始化

ArrayList無參數初始化

在使用無參構造器初始化時,從源碼可以看出指向的是默認容量大小的object數組,需要注意的是在使用無參數初始化時並沒有直接創建容量為10的object數組,而是使用了上面提到的“懶加載”策略,使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA(默認容量為0)作為標識,在執行add()操作的時候才會開闢object數組。

默認容量(DEFAULTCAPACITY_EMPTY_ELEMENTDATA)的處理邏輯在ArrayList的擴容函數中,源碼如下:


ArrayList源碼解析之初始化

ArrayList擴容函數

從源碼中可以看出如果最小容量不是默認元素表,就可以是任意大小。

1.2 指定大小初始化

指定大小初始化是指在構建時指定一個初始化大小,源碼如下:

ArrayList源碼解析之初始化

ArrayList指定大小初始化

這裡穿插一個知識點,可以從源碼中看到size沒有使用volatile修飾,所以事非線程安全的。

指定初始化大小構造器是最常用的構造器之一,實際上就是創建了一個指定大小的object數組,用來存放後續add()的元素。

1.3 指定初始化數據初始化

ArrayList的第三種初始化方式就是指定一個初始化數據進行初始化,源碼如下:

ArrayList源碼解析之初始化

指定初始化數據初始化

在使用指定初始化數據時,可以看到源碼中有這樣一條語句:elementData = c.toArray();在jdk8中,這是Java的一個bug,具體bug官方解釋如下圖(官方地址為:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652,bugId是6260652):

ArrayList源碼解析之初始化

ArrayList初始化bug6260652

ArrayList源碼解析之初始化

bug描述

在一般情況下是不會觸發此bug的,根據官方給出的解釋,只有在如下場景才會觸發:ArrayList初始化之後,再次調用toArray函數,得到一個object數組,如果此時給object數組賦值,就會觸發這個bug。

ArrayList源碼解析之初始化

如果感興趣可以使用下面代碼測試:

<code>package com.study.base.demo.entity;

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

/**
 * 

Title: ArrayListOfBug

*

Description: ArrayList初始化中的bug 6260652

*

Company: http://www.yinjiedu.com

*

Project: base

* * @author: WEIQI * @Date: 2020-2-3 21:05 * @Version: 1.0 */ @Slf4j public class ArrayListOfBug { public static void main(String[] args) { List list = Arrays.asList("array list bug"); log.info("list is {}", list); Object[] objects = list.toArray(); objects[1] = new Object(); } } /<code>

需要注意的是我在項目中引入了lombok依賴,如果@Slf4j報錯是因為沒有引入依賴導致。

謝謝大家閱讀,有不足之處,煩請指出,我會及時修正。瞭解更多文章歡迎關注微信公眾號《編程之藝術》!


分享到:


相關文章: