Java集合系列(二):ArrayList、LinkedList、Vector的使用方法及區別
本篇部落格主要講解List介面的三個實現類ArrayList、LinkedList、Vector的使用方法以及三者之間的區別。
1. ArrayList使用
ArrayList是List介面最常用的實現類,內部通過陣列來實現,因此它的優點是適合隨機查詢和遍歷,缺點是不適合插入和刪除。
ArrayList類的程式碼宣告如下所示:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { ...... }
1.1 新增元素
使用ArrayList新增元素有以下兩個過載:
boolean add(E e);
void add(int index, E element);
boolean add(E e);
是將元素新增到集合的末尾,
void add(int index, E element);
是將元素新增到指定的索引位置(索引是從0開始的)。
使用方法如下所示:
List<String> platformList = new ArrayList<>(); // 新增元素 platformList.add("部落格園"); platformList.add("掘金"); platformList.add("微信公眾號"); // 新增重複元素,會新增成功,因為List支援新增重複元素 platformList.add("部落格園"); platformList.add("掘金"); platformList.add(3, "個人部落格");
1.2 獲取元素
獲取ArrayList中指定索引處的元素的使用方法如下所示:
System.out.println("索引為3的元素為:" + platformList.get(3));
如果指定的索引超出了集合的最大索引,比如platformList.get(6)
就會丟擲異常java.lang.IndexOutOfBoundsException
:
1.3 獲取集合元素個數
獲取ArrayList元素個數的使用方法如下所示:
System.out.println("platformList的元素個數為:" + platformList.size());
1.4 刪除元素
使用ArrayList刪除元素有以下兩個過載:
E remove(int index);
boolean remove(Object o);
E remove(int index);
是刪除集合中指定索引處的元素,boolean remove(Object o);
是刪除集合中的指定元素。
使用方法如下所示:
// 指定索引刪除重複的元素 "部落格園" "掘金"
platformList.remove(4);
platformList.remove(4);
// 刪除指定元素 "個人部落格"
platformList.remove("個人部落格");
1.5 修改元素
修改ArrayList中指定索引處的元素值的使用方法如下所示:
platformList.set(0, "部落格園:https://www.cnblogs.com/zwwhnly/");
platformList.set(1, "掘金:https://juejin.im/user/5c7ce730f265da2dca388167");
platformList.set(2, "微信公眾號:申城異鄉人");
1.6 判斷集合是否為空
判斷ArrayList是否為空的使用方法如下所示:
System.out.println("isEmpty:" + platformList.isEmpty());
1.7 遍歷元素(面試常問)
遍歷ArrayList的元素主要有以下3種方式:
- 迭代器遍歷
- for迴圈
- foreach迴圈
使用方法如下所示:
System.out.println("使用Iterator遍歷:");
Iterator<String> platformIterator = platformList.iterator();
while (platformIterator.hasNext()) {
System.out.println(platformIterator.next());
}
System.out.println();
System.out.println("使用for迴圈遍歷:");
for (int i = 0; i < platformList.size(); i++) {
System.out.println(platformList.get(i));
}
System.out.println();
System.out.println("使用foreach遍歷:");
for (String platform : platformList) {
System.out.println(platform);
}
1.8 清空集合
清空ArrayList中所有元素的使用方法如下所示:
platformList.clear();
1.9 完整示例程式碼
上面講解的幾點,完整程式碼如下所示:
public static void main(String[] args) {
List<String> platformList = new ArrayList<>();
// 新增元素
platformList.add("部落格園");
platformList.add("掘金");
platformList.add("微信公眾號");
// 新增重複元素,會新增成功,因為List支援新增重複元素
platformList.add("部落格園");
platformList.add("掘金");
platformList.add(3, "個人部落格");
System.out.println("索引為3的元素為:" + platformList.get(3));
System.out.println("platformList的元素個數為:" + platformList.size());
// 指定索引刪除重複的元素 "部落格園" "掘金"
platformList.remove(4);
platformList.remove(4);
// 刪除指定元素 "個人部落格"
platformList.remove("個人部落格");
System.out.println("platformList的元素個數為:" + platformList.size());
platformList.set(0, "部落格園:https://www.cnblogs.com/zwwhnly/");
platformList.set(1, "掘金:https://juejin.im/user/5c7ce730f265da2dca388167");
platformList.set(2, "微信公眾號:申城異鄉人");
System.out.println("isEmpty:" + platformList.isEmpty());
System.out.println("使用Iterator遍歷:");
Iterator<String> platformIterator = platformList.iterator();
while (platformIterator.hasNext()) {
System.out.println(platformIterator.next());
}
System.out.println();
System.out.println("使用for迴圈遍歷:");
for (int i = 0; i < platformList.size(); i++) {
System.out.println(platformList.get(i));
}
System.out.println();
System.out.println("使用foreach遍歷:");
for (String platform : platformList) {
System.out.println(platform);
}
System.out.println();
// 清空集合
platformList.clear();
System.out.println("isEmpty:" + platformList.isEmpty());
}
輸出結果為:
索引為3的元素為:個人部落格
platformList的元素個數為:6
platformList的元素個數為:3
isEmpty:false
使用Iterator遍歷:
部落格園:https://www.cnblogs.com/zwwhnly/
掘金:https://juejin.im/user/5c7ce730f265da2dca388167
微信公眾號:申城異鄉人
使用for迴圈遍歷:
部落格園:https://www.cnblogs.com/zwwhnly/
掘金:https://juejin.im/user/5c7ce730f265da2dca388167
微信公眾號:申城異鄉人
使用foreach遍歷:
部落格園:https://www.cnblogs.com/zwwhnly/
掘金:https://juejin.im/user/5c7ce730f265da2dca388167
微信公眾號:申城異鄉人
isEmpty:true
2. LinkedList使用
LinkedList也是List介面的實現類,內部使用連結串列結構儲存資料,因此它的優點是適合動態插入和刪除元素,缺點是隨機查詢和遍歷速度比較慢。
LinkedList類的程式碼宣告如下所示:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
}
LinkedList類的使用方法和ArrayList基本一樣,只需修改下宣告處的程式碼即可:
List<String> platformList = new LinkedList<>();
3. Vector使用
Vector也是List介面的實現類,內部也是通過陣列來實現。
Vector類的程式碼宣告如下所示:
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
}
與ArrayList不同的是,Vector是執行緒安全的,即某一時刻只有一個執行緒能夠寫Vector,避免多執行緒同時寫而引起的不一致性。不過這也造成Vector的缺點:實現執行緒的同步需要額外的花費,因此它的訪問速度會比ArrayList慢一些。
可以認為Vector是ArrayList在多執行緒環境下的實現版本。
所以Vector類的使用方法和ArrayList基本一樣,只需修改下宣告處的程式碼即可:
List<String> platformList = new Vector<>();
由於要支援執行緒同步,因此Vector類的很多方法都有synchronized關鍵字,如下所示:
public synchronized boolean isEmpty() {
return elementCount == 0;
}
public synchronized int size() {
return elementCount;
}
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
4. ArrayList、LinkedList、Vector的區別(面試常問)
注意:以下程式碼使用的JDK版本為1.8.0_191
4.1 相同點
ArrayList、LinkedList、Vector都實現了List介面,所以使用方式很類似,通過上面的示例也能發現這一點。
4.2 不同點
但是ArrayList、LinkedList、Vector的內部實現方式不同,也就導致了它們之間是有區別的。
4.2.1 儲存結構
ArrayList和Vector是基於陣列實現的,LinkedList是基於雙向連結串列實現的。
這也就導致ArrayList適合隨機查詢和遍歷,而LinkedList適合動態插入和刪除元素。
關於陣列和雙向連結串列,這裡不做詳解,後續會單獨寫篇文章總結。
4.2.2 執行緒安全性
ArrayList和LinkedList是執行緒不安全的,Vector是執行緒安全的。
Vector可以看做是ArrayList在多執行緒環境下的另一種實現方式,這也導致了Vector的效率沒有ArraykList和LinkedList高。
如果要在併發環境下使用ArrayList或者LinkedList,可以呼叫Collections類的synchronizedList()方法:
Collections.synchronizedList(platformList);
4.2.3 擴容機制
ArrayList和Vector都是使用Object型別的陣列來儲存資料的,ArrayList的預設容量是0,Vector的預設容量是10。
空說無憑,我們先看下ArrayList的使用示例:
List<String> strArrayList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
strArrayList.add(String.valueOf(i));
}
執行的ArrayList建構函式的原始碼為:
transient Object[] elementData;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
再看下Vector的使用示例:
List<String> strVector = new Vector<>();
for (int i = 0; i < 30; i++) {
strVector.add(String.valueOf(i));
}
執行的Vector建構函式的原始碼為:
protected Object[] elementData;
protected int capacityIncrement;
public Vector() {
this(10);
}
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
當向這兩種型別中新增元素時,若容量不夠,就會進行擴容,擴容的本質是產生一個新陣列,將原陣列的資料複製到新陣列,再將新的元素新增到新陣列中,使用的方法是Arrays.copyOf()
,其中ArrayList擴容後的容量是之前的1.5倍,Vector預設情況下擴容後的容量是之前的2倍。
仍然使用上面的ArrayList的例子:
List<String> strArrayList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
strArrayList.add(String.valueOf(i));
}
在執行完List<String> strArrayList = new ArrayList<>();
後,此時strArrayList的容量是0,
然後在新增第1個元素時,strArrayList的容量會擴容為容量10,
當新增第11個元素時,strArrayList的容量會擴容為容量15,
當新增第16個元素時,strArrayList的容量會擴容為容量22,
如果還需要擴容,依次會擴容到33-->49。
看下ArrayList的原始碼,就明白為什麼會這樣擴容:
private static final int DEFAULT_CAPACITY = 10;
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
最核心的程式碼就是int newCapacity = oldCapacity + (oldCapacity >> 1);
,所以ArrayList擴容後的容量是之前的1.5倍。
再看下上面的Vector例子:
List<String> strVector = new Vector<>();
for (int i = 0; i < 30; i++) {
strVector.add(String.valueOf(i));
}
在執行完List<String> strVector = new Vector<>();
後,此時strVector的容量是10,
當新增第11個元素時,strVector的容量會擴容為容量20,
當新增第21個元素時,strVector的容量會擴容為容量40,
如果還需要擴容,依次會擴容到80-->160。
看下Vector的原始碼,就明白為什麼會這樣擴容:
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
最核心的程式碼就是int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);
,所以Vector預設情況下擴容後的容量是之前的2倍。
4.2.4 效率
ArrayList隨機查詢和遍歷的效率會高一些,但動態插入和刪除元素的效率會低一些。
LinkedList動態插入和刪除元素的效率會高一些,但隨機查詢和遍歷的效率會低一些。
如果需要在多執行緒下操作集合元素,建議使用Vector,否則的話,建議使用ArrayList。
5. 原始碼及參考
ArrayList、LinkedList、Vector的區別和實現原理
Java深入 - 深入理解Java集合
Java進階(四十六)簡述ArrayList、Vector與LinkedList的異同點
6. 最後
打個小廣告,歡迎掃碼關注微信公眾號:「申城異鄉人」,定期分享Java技術乾貨,讓我們一起進步。
相關推薦
Java集合系列(二):ArrayList、LinkedList、Vector的使用方法及區別
本篇部落格主要講解List介面的三個實現類ArrayList、LinkedList、Vector的使用方法以及三者之間的區別。 1. ArrayList使用 ArrayList是List介面最常用的實現類,內部通過陣列來實現,因此它的優點是適合隨機查詢和遍歷,缺點是不適合插入和刪除。 ArrayList類的程
深入理解JAVA集合系列四:ArrayList源碼解讀
結束 了解 數組下標 size new 數組元素 開始 ini rem 在開始本章內容之前,這裏先簡單介紹下List的相關內容。 List的簡單介紹 有序的collection,用戶可以對列表中每個元素的插入位置進行精確的控制。用戶可以根據元素的整數索引(在列表中的位置)訪
java集合【12】——— ArrayList,LinkedList,Vector的相同點與區別是什麼?
[TOC] 要想回答這個問題,可以先把各種都講特性,然後再從底層儲存結構,執行緒安全,預設大小,擴容機制,迭代器,增刪改查效率這幾個方向入手。 ## 特性列舉 ![](https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/2021030602125
java集合之列表:ArrayList、Vector、LinkedList
sta pop arraylist 允許 dex nsa pack java jdk 1 package com.jdk7.chapter4; 2 3 import java.util.ArrayList; 4 import java.util.Link
Java 集合系列08之 List總結(LinkedList, ArrayList等使用場景和效能分析)
1 import java.util.*; 2 import java.lang.Class; 3 4 /* 5 * @desc 對比ArrayList和LinkedList的插入、隨機讀取效率、刪除的效率 6 * 7 * @author skywang 8 */ 9 public
Java 集合系列08之 List總結(LinkedList, ArrayList等使用場景和性能分
index索引 不同之處 知識點 給未來的自己 zab 默認 性能調優 程序 代碼 第1部分 List概括 先回顧一下List的框架圖 (01) List 是一個接口,它繼承於Collection的接口。它代表著有序的隊列。 (02) AbstractList 是一個抽象類
Java集合系列(三):HashSet、LinkedHashSet、TreeSet的使用方法及區別
本篇部落格主要講解Set介面的三個實現類HashSet、LinkedHashSet、TreeSet的使用方法以及三者之間的區別。 注意:本文中程式碼使用的JDK版本為1.8.0_191 1. HashSet使用 HashSet是Set介面最常用的實現類,底層資料結構是雜湊表,HashSet不保證元素的順序
Java集合系列(四):HashMap、Hashtable、LinkedHashMap、TreeMap的使用方法及區別
本篇部落格主要講解Map介面的4個實現類HashMap、Hashtable、LinkedHashMap、TreeMap的使用方法以及三者之間的區別。 注意:本文中程式碼使用的JDK版本為1.8.0_191 值得注意的是,Map介面是獨立的介面,並沒有繼承Collection介面(這裡是重點,面試常問):
深入理解JAVA集合系列三:HashMap的死循環解讀
現在 最新 star and 場景 所有 image cap 時也 由於在公司項目中偶爾會遇到HashMap死循環造成CPU100%,重啟後問題消失,隔一段時間又會反復出現。今天在這裏來仔細剖析下多線程情況下HashMap所帶來的問題: 1、多線程put操作後,get操作導
java集合的實現細節--ArrayList和LinkedList
方法 封裝 對象 通過 場景 部分 index索引 ava 本質 ArrayList和LinkedList的實現差異 List代表一種線性表的數據結構,ArrayList則是一種順序存儲的線性表,ArrayList底層采用動態數組的形式保存每一個集合元素,Link
Java 集合系列03之 ArrayList詳細介紹
ArrayList做為List介面中最常用的實現類,必須掌握。 一、ArrayList簡介 與Java中的陣列相比ArrayList的容量可以動態增加。它繼承與AbstractList,實現了List, RandomAccess, Cloneable, java.io.Serializable 和Vec
java資料結構之:ArrayList與LinkedList詳解
前篇博文講到了Java底層怎麼知道ArrayList和LinkedList哪個是隨機訪問哪個是順序訪問的,本片博文主要介紹各自的資料特點。 ArrayList: 從他的這個建構函式我們可以知道他的底層實現就是一個Object物件陣列。 第二個建構函式構造一個空的
Java 集合系列03之 ArrayList詳細介紹(原始碼解析)和使用示例
概要 上一章,我們學習了Collection的架構。這一章開始,我們對Collection的具體實現類進行講解;首先,講解List,而List中ArrayList又最為常用。因此,本章我們講解ArrayList。先對ArrayList有個整體認識,再學習它的原始
java基礎梳理二:基本資料型別、變數
1、基本資料型別 分為四大類: 佔用位元組數①整數型別byte:位元組型別 1short:短整型 2int:整型 4long:長整型 8②浮點數型別float:單精度
Java爬蟲系列二:使用HttpClient抓取頁面HTML
爬蟲要想爬取需要的資訊,首先第一步就要抓取到頁面html內容,然後對html進行分析,獲取想要的內容。上一篇隨筆《Java爬蟲系列一:寫在開始前》中提到了HttpClient可以抓取頁面內容。 今天就來介紹下抓取html內容的工具:HttpClient。 圍繞下面幾個點展開: 什麼是HttpCl
Java集合系列(一):集合的定義及分類
1. 集合的定義 什麼是集合呢? 定義:集合是一個存放物件的引用的容器。 在Java中,集合位於java.util包下。 2. 集合和陣列的區別(面試常問) 提到容器,就會想起陣列,那麼集合和陣列的區別是什麼呢?(這裡是重點,面試可能問的比較多) 陣列和集合都是Java中的容器 陣列的長度是固定的,集合的長
PHP中 Public、Private、Protect 的使用方法及區別
public 【公共的】 可以在程式中的任何位置(類內、類外)被其他的類和物件呼叫。子類可以繼承和使用父類中所有的公共成員。 Private 【私有的】 被private修飾的變數和方法,只能在所在的類的內部被呼叫和修改,不可以在類的外部被訪問。在子類中也不可以。 如
Java 集合系列: ArrayList詳細介紹(源碼解析)和使用示例
java 集合 概要 上一章,我們學習了Collection的架構。這一章開始,我們對Collection的具體實現類進行講解;首先,講解List,而List中ArrayList又最為常用。因此,本章我們講解ArrayList。先對ArrayList有個整體認識,再學習它的源碼,最後再通過例子來學習如
java集合系列——List集合之ArrayList介紹(二)
一:List概述 List是 java.util包下面的類,從 java集合系列——java集合概述(一) 中可以知道,List繼承了Collection 介面! List本身也是一個介面,它的實現有ArrayList 、LinkedList、Vector和CopyOn
Java 中集合型別包含ArrayList、LinkedList、HashMap等類,下列描述正確的是(多選)?
A.ArrayList與LinkedList都實現了List介面B.刪除元素時,ArrayList的表現更佳C.ArrayList的訪問速度比LinkedList快D.HashMap實現Map介面,允許任何型別的鍵和值物件,並且允許鍵和值都為null答案:ACD擴充套件:瞭解