亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java集合系列之ArrayList源碼分析

 更新時(shí)間:2018年02月27日 11:23:16   作者:勞夫子  
這篇文章主要為大家詳細(xì)介紹了Java集合系列之ArrayList源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本篇分析ArrayList的源碼,在分析之前先跟大家談一談數(shù)組。數(shù)組可能是我們最早接觸到的數(shù)據(jù)結(jié)構(gòu)之一,它是在內(nèi)存中劃分出一塊連續(xù)的地址空間用來(lái)進(jìn)行元素的存儲(chǔ),由于它直接操作內(nèi)存,所以數(shù)組的性能要比集合類更好一些,這是使用數(shù)組的一大優(yōu)勢(shì)。但是我們知道數(shù)組存在致命的缺陷,就是在初始化時(shí)必須指定數(shù)組大小,并且在后續(xù)操作中不能再更改數(shù)組的大小。在實(shí)際情況中我們遇到更多的是一開(kāi)始并不知道要存放多少元素,而是希望容器能夠自動(dòng)的擴(kuò)展它自身的容量以便能夠存放更多的元素。ArrayList就能夠很好的滿足這樣的需求,它能夠自動(dòng)擴(kuò)展大小以適應(yīng)存儲(chǔ)元素的不斷增加。它的底層是基于數(shù)組實(shí)現(xiàn)的,因此它具有數(shù)組的一些特點(diǎn),例如查找修改快而插入刪除慢。本篇我們將深入源碼看看它是怎樣對(duì)數(shù)組進(jìn)行封裝的。首先看看它的成員變量和三個(gè)主要的構(gòu)造器。

//默認(rèn)初始化容量
private static final int DEFAULT_CAPACITY = 10;

//空對(duì)象數(shù)組
private static final Object[] EMPTY_ELEMENTDATA = {};

//對(duì)象數(shù)組
private transient Object[] elementData;

//集合元素個(gè)數(shù)
private int size;

//傳入初始容量的構(gòu)造方法
public ArrayList(int initialCapacity) {
  super();
  if (initialCapacity < 0) {
    throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
  }
  //新建指定容量的Object類型數(shù)組
  this.elementData = new Object[initialCapacity];
}

//不帶參數(shù)的構(gòu)造方法
public ArrayList() {
  super();
  //將空的數(shù)組實(shí)例傳給elementData
  this.elementData = EMPTY_ELEMENTDATA;
}

//傳入外部集合的構(gòu)造方法
public ArrayList(Collection<? extends E> c) {
  //持有傳入集合的內(nèi)部數(shù)組的引用
  elementData = c.toArray();
  //更新集合元素個(gè)數(shù)大小
  size = elementData.length;
  //判斷引用的數(shù)組類型, 并將引用轉(zhuǎn)換成Object數(shù)組引用
  if (elementData.getClass() != Object[].class) {
    elementData = Arrays.copyOf(elementData, size, Object[].class);
  }
}

可以看到ArrayList的內(nèi)部存儲(chǔ)結(jié)構(gòu)就是一個(gè)Object類型的數(shù)組,因此它可以存放任意類型的元素。在構(gòu)造ArrayList的時(shí)候,如果傳入初始大小那么它將新建一個(gè)指定容量的Object數(shù)組,如果不設(shè)置初始大小那么它將不會(huì)分配內(nèi)存空間而是使用空的對(duì)象數(shù)組,在實(shí)際要放入元素時(shí)再進(jìn)行內(nèi)存分配。下面再看看它的增刪改查方法。

//增(添加)
public boolean add(E e) {
  //添加前先檢查是否需要拓展數(shù)組, 此時(shí)數(shù)組長(zhǎng)度最小為size+1
  ensureCapacityInternal(size + 1);
  //將元素添加到數(shù)組末尾
  elementData[size++] = e;
  return true;
}


//增(插入)
public void add(int index, E element) {
  //插入位置范圍檢查
  rangeCheckForAdd(index);
  //檢查是否需要擴(kuò)容
  ensureCapacityInternal(size + 1);
  //挪動(dòng)插入位置后面的元素
  System.arraycopy(elementData, index, elementData, index + 1, size - index);
  //在要插入的位置賦上新值
  elementData[index] = element;
  size++;
}

//刪
public E remove(int index) {
  //index不能大于size
  rangeCheck(index);
  modCount++;
  E oldValue = elementData(index);
  int numMoved = size - index - 1;
  if (numMoved > 0) {
    //將index后面的元素向前挪動(dòng)一位
    System.arraycopy(elementData, index+1, elementData, index, numMoved);
  }
  //置空引用
  elementData[--size] = null;
  return oldValue;
}

//改
public E set(int index, E element) {
  //index不能大于size
  rangeCheck(index);
  E oldValue = elementData(index);
  //替換成新元素
  elementData[index] = element;
  return oldValue;
}

//查
public E get(int index) {
  //index不能大于size
  rangeCheck(index);
  //返回指定位置元素
  return elementData(index);
}

每次添加一個(gè)元素到集合中都會(huì)先檢查容量是否足夠,否則就進(jìn)行擴(kuò)容,擴(kuò)容的細(xì)節(jié)下面會(huì)講到。我們先看具體增刪改查要注意的地方。
增(添加):僅是將這個(gè)元素添加到末尾。操作快速。
增(插入):由于需要移動(dòng)插入位置后面的元素,并且涉及數(shù)組的復(fù)制,所以操作較慢。
刪:由于需要將刪除位置后面的元素向前挪動(dòng),也會(huì)設(shè)計(jì)數(shù)組復(fù)制,所以操作較慢。
改:直接對(duì)指定位置元素進(jìn)行修改,不涉及元素挪動(dòng)和數(shù)組復(fù)制,操作快速。
查:直接返回指定下標(biāo)的數(shù)組元素,操作快速。
通過(guò)源碼看到,由于查找和修改直接定位到數(shù)組下標(biāo),不涉及元素挪動(dòng)和數(shù)組復(fù)制所以較快,而插入刪除由于要挪動(dòng)元素,涉及到數(shù)組復(fù)制,操作較慢。并且每次添加操作還可能進(jìn)行數(shù)組擴(kuò)容,也會(huì)影響到性能。下面我們看看ArrayList是怎樣動(dòng)態(tài)擴(kuò)容的。

private void ensureCapacityInternal(int minCapacity) {
  //如果此時(shí)還是空數(shù)組
  if (elementData == EMPTY_ELEMENTDATA) {
    //和默認(rèn)容量比較, 取較大值
    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  }
  //數(shù)組已經(jīng)初始化過(guò)就執(zhí)行這一步
  ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
  modCount++;
  //如果最小容量大于數(shù)組長(zhǎng)度就擴(kuò)增數(shù)組
  if (minCapacity - elementData.length > 0) {
    grow(minCapacity);
  }
}

//集合最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

//增加數(shù)組長(zhǎng)度
private void grow(int minCapacity) {
  //獲取數(shù)組原先的容量
  int oldCapacity = elementData.length;
  //新數(shù)組的容量, 在原來(lái)的基礎(chǔ)上增加一半
  int newCapacity = oldCapacity + (oldCapacity >> 1);
  //檢驗(yàn)新的容量是否小于最小容量
  if (newCapacity - minCapacity < 0) {
    newCapacity = minCapacity;
  }
  //檢驗(yàn)新的容量是否超過(guò)最大數(shù)組容量
  if (newCapacity - MAX_ARRAY_SIZE > 0) {
    newCapacity = hugeCapacity(minCapacity);
  }
  //拷貝原來(lái)的數(shù)組到新數(shù)組
  elementData = Arrays.copyOf(elementData, newCapacity);
}

每次添加元素前會(huì)調(diào)用ensureCapacityInternal這個(gè)方法進(jìn)行集合容量檢查。在這個(gè)方法內(nèi)部會(huì)檢查當(dāng)前集合的內(nèi)部數(shù)組是否還是個(gè)空數(shù)組,如果是就新建默認(rèn)大小為10的Object數(shù)組。如果不是則證明當(dāng)前集合已經(jīng)被初始化過(guò),那么就調(diào)用ensureExplicitCapacity方法檢查當(dāng)前數(shù)組的容量是否滿足這個(gè)最小所需容量,不滿足的話就調(diào)用grow方法進(jìn)行擴(kuò)容。在grow方法內(nèi)部可以看到,每次擴(kuò)容都是增加原來(lái)數(shù)組長(zhǎng)度的一半,擴(kuò)容實(shí)際上是新建一個(gè)容量更大的數(shù)組,將原先數(shù)組的元素全部復(fù)制到新的數(shù)組上,然后再拋棄原先的數(shù)組轉(zhuǎn)而使用新的數(shù)組。至此,我們對(duì)ArrayList中比較常用的方法做了分析,其中有些值得注意的要點(diǎn):

1. ArrayList底層實(shí)現(xiàn)是基于數(shù)組的,因此對(duì)指定下標(biāo)的查找和修改比較快,但是刪除和插入操作比較慢。
2. 構(gòu)造ArrayList時(shí)盡量指定容量,減少擴(kuò)容時(shí)帶來(lái)的數(shù)組復(fù)制操作,如果不知道大小可以賦值為默認(rèn)容量10。
3. 每次添加元素之前會(huì)檢查是否需要擴(kuò)容,每次擴(kuò)容都是增加原有容量的一半。
4. 每次對(duì)下標(biāo)的操作都會(huì)進(jìn)行安全性檢查,如果出現(xiàn)數(shù)組越界就立即拋出異常。
5. ArrayList的所有方法都沒(méi)有進(jìn)行同步,因此它不是線程安全的。
6. 以上分析基于JDK1.7,其他版本會(huì)有些出入,因此不能一概而論。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)評(píng)論回復(fù)功能的完整步驟

    Java實(shí)現(xiàn)評(píng)論回復(fù)功能的完整步驟

    這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)評(píng)論回復(fù)功能的完整步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java中final與繼承操作實(shí)例分析

    Java中final與繼承操作實(shí)例分析

    這篇文章主要介紹了Java中final與繼承操作,結(jié)合實(shí)例形式分析了Java中使用final阻止繼承的相關(guān)原理與操作注意事項(xiàng),需要的朋友可以參考下
    2019-09-09
  • 啟動(dòng)Solr提示Java版本低問(wèn)題解決方案

    啟動(dòng)Solr提示Java版本低問(wèn)題解決方案

    這篇文章主要介紹了啟動(dòng)Solr提示Java版本低問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Spring實(shí)戰(zhàn)之使用靜態(tài)工廠方法創(chuàng)建Bean操作示例

    Spring實(shí)戰(zhàn)之使用靜態(tài)工廠方法創(chuàng)建Bean操作示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之使用靜態(tài)工廠方法創(chuàng)建Bean操作,結(jié)合實(shí)例形式分析了靜態(tài)工廠方法創(chuàng)建Bean的相關(guān)實(shí)現(xiàn)步驟與操作注意事項(xiàng),需要的朋友可以參考下
    2019-11-11
  • Java?stream流中peek用法簡(jiǎn)單示例

    Java?stream流中peek用法簡(jiǎn)單示例

    這篇文章主要給大家介紹了關(guān)于Java?stream流中peek用法的相關(guān)資料,Java Stream中的peek()方法也是用于查看每個(gè)元素,但不改變流的操作的方法,文中通過(guò)代碼介紹的需要的朋友可以參考下
    2023-12-12
  • SpringBoot如何讀取war包jar包和Resource資源

    SpringBoot如何讀取war包jar包和Resource資源

    這篇文章主要介紹了SpringBoot如何讀取war包jar包和Resource資源,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Java中ArrayList集合的常用方法大全

    Java中ArrayList集合的常用方法大全

    這篇文章主要給大家介紹了關(guān)于Java中ArrayList集合的常用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 運(yùn)行Jar包出現(xiàn)提示xxx中沒(méi)有主清單屬性報(bào)錯(cuò)問(wèn)題解決方法

    運(yùn)行Jar包出現(xiàn)提示xxx中沒(méi)有主清單屬性報(bào)錯(cuò)問(wèn)題解決方法

    這篇文章主要介紹了運(yùn)行Jar包出現(xiàn):xxx中沒(méi)有主清單屬性報(bào)錯(cuò),當(dāng)出現(xiàn)報(bào)錯(cuò):xxx中沒(méi)有主清單屬性,解決方法也很簡(jiǎn)單,在pom.xml配置中,加上相應(yīng)配置即可,需要的朋友可以參考下
    2023-08-08
  • Spring項(xiàng)目中swagger用法與swagger-ui使用

    Spring項(xiàng)目中swagger用法與swagger-ui使用

    這篇文章主要介紹了Spring項(xiàng)目中swagger用法與swagger-ui使用,通過(guò)圖文并茂的形式給大家介紹了編寫springboot項(xiàng)目的方法及導(dǎo)入spring-fox依賴的代碼詳解,需要的朋友可以參考下
    2021-05-05
  • Spring框架JdbcTemplate數(shù)據(jù)庫(kù)事務(wù)管理完全注解方式

    Spring框架JdbcTemplate數(shù)據(jù)庫(kù)事務(wù)管理完全注解方式

    這篇文章主要介紹了Spring框架JdbcTemplate數(shù)據(jù)庫(kù)事務(wù)管理及完全注解方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05

最新評(píng)論