Java數(shù)據(jù)結(jié)構(gòu)之ArrayList從順序表到實現(xiàn)
1 ArrayList
在集合框架中,ArrayList是一個普通的類,實現(xiàn)了List接口,具體框架圖如下:

說明:
- ArrayList實現(xiàn)了RandomAccess接口,表明ArrayList支持隨機訪問
- ArrayList實現(xiàn)了Cloneable接口,表明ArrayList是可以clone的
- ArrayList實現(xiàn)了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是線程安全的,在單線程下可以使用,在多線程中可以選擇Vector或者CopyOnWriteArrayList
- ArrayList底層是一段連續(xù)的空間,并且可以動態(tài)擴容,是一個動態(tài)類型的順序表
2 ArrayList使用
2.1 ArrayList的構(gòu)造
| 方法 | 解釋 |
|---|---|
| ArrayList() | 無參構(gòu)造 |
| ArrayList(Collection<? extends E> c) | 利用其他 Collection 構(gòu)建 ArrayList |
| ArrayList(int initialCapacity) | 指定順序表初始容量 |
public static void main(String[] args) {
// ArrayList創(chuàng)建,推薦寫法
// 構(gòu)造一個空的列表
List<Integer> list1 = new ArrayList<>();
// 構(gòu)造一個具有10個容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 編譯失敗,List<Integer>已經(jīng)限定了,list2中只能存儲整形元素
// list3構(gòu)造好之后,與list中的元素一致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略類型,否則:任意類型的元素都可以存放,使用時將是一場災(zāi)難
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}
2.2 ArrayList常見操作
| 方法 | 解釋 |
|---|---|
| boolean add(E e) | 尾插 e |
| void add(int index, E element) | 將 e 插入到 index 位置 |
| boolean addAll(Collection<? extends E> c) | 尾插 c 中的元素 |
| E remove(int index) | 刪除 index 位置元素 |
| boolean remove(Object o) | 刪除遇到的第一個 o |
| E get(int index) | 獲取下標(biāo) index 位置元素 |
| E set(int index, E element) | 將下標(biāo) index 位置元素設(shè)置為 element |
| void clear() | 清空 |
| boolean contains(Object o) | 判斷 o 是否在線性表中 |
| int indexOf(Object o) | 返回第一個 o 所在下標(biāo) |
| int lastIndexOf(Object o) | 返回最后一個 o 的下標(biāo) |
| List subList(int fromIndex, int toIndex) | 截取部分 list |
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("JavaSE");
list.add("JavaWeb");
list.add("JavaEE");
list.add("JVM");
list.add("測試課程");
System.out.println(list);
// 獲取list中有效元素個數(shù)
System.out.println(list.size());
// 獲取和設(shè)置index位置上的元素,注意index必須介于[0, size)間
System.out.println(list.get(1));
list.set(1, "JavaWEB");
System.out.println(list.get(1));
// 在list的index位置插入指定元素,index及后續(xù)的元素統(tǒng)一往后搬移一個位置
list.add(1, "Java數(shù)據(jù)結(jié)構(gòu)");
System.out.println(list);
// 刪除指定元素,找到了就刪除,該元素之后的元素統(tǒng)一往前搬移一個位置
list.remove("JVM");
System.out.println(list);
// 刪除list中index位置上的元素,注意index不要超過list中有效元素個數(shù),否則會拋出下標(biāo)越界異常
list.remove(list.size()-1);
System.out.println(list);
//輸出結(jié)果:
[JavaSE, JavaWeb, JavaEE, JVM, 測試課程]
5
JavaWeb
JavaWEB
[JavaSE, Java數(shù)據(jù)結(jié)構(gòu), JavaWEB, JavaEE, JVM, 測試課程]
[JavaSE, Java數(shù)據(jù)結(jié)構(gòu), JavaWEB, JavaEE, 測試課程]
[JavaSE, Java數(shù)據(jù)結(jié)構(gòu), JavaWEB, JavaEE]
2.3 ArrayList的遍歷
ArrayList 可以使用三方方式遍歷:for循環(huán)+下標(biāo)、foreach、使用迭代器
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 使用下標(biāo)+for遍歷
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
// 借助foreach遍歷
for (Integer integer : list) {
System.out.print(integer + " ");
}
System.out.println();
Iterator<Integer> it = list.listIterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
System.out.println();
}
//輸出結(jié)果:
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
2.4 ArrayList的擴容機制
ArrayList是一個動態(tài)類型的順序表,即:在插入元素的過程中會自動擴容:以下是ArrayList源碼中擴容方式
Object[] elementData; // 存放元素的空間
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默認空間
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 static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 獲取舊空間大小
int oldCapacity = elementData.length;
// 預(yù)計按照1.5倍方式擴容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用戶需要擴容大小 超過 原空間1.5倍,按照用戶所需大小擴容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果需要擴容大小超過MAX_ARRAY_SIZE,重新計算容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 調(diào)用copyOf擴容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
// 如果minCapacity小于0,拋出OutOfMemoryError異常
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
檢測是否真正需要擴容,如果是調(diào)用grow準(zhǔn)備擴容
預(yù)估需要庫容的大小
- 初步預(yù)估按照1.5倍大小擴容
- 如果用戶所需大小超過預(yù)估1.5倍大小,則按照用戶所需大小擴容
- 真正擴容之前檢測是否能擴容成功,防止太大導(dǎo)致擴容失敗
使用copyOf進行擴容
3 使用示例
撲克牌:
public class Card {
public int rank; // 牌面值
public String suit; // 花色
@Override
public String toString() {
return String.format("[%s %d]", suit, rank);
}
}
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
public class CardDemo {
public static final String[] SUITS = {"?", "?", "?", "?"};
// 買一副牌
private static List<Card> buyDeck() {
List<Card> deck = new ArrayList<>(52);
for (int i = 0; i < 4; i++) {
for (int j = 1; j <= 13; j++) {
String suit = SUITS[i];
int rank = j;
Card card = new Card();
card.rank = rank;
card.suit = suit;
deck.add(card);
}
}
return deck;
}
private static void swap(List<Card> deck, int i, int j) {
Card t = deck.get(i);
deck.set(i, deck.get(j));
deck.set(j, t);
}
private static void shuffle(List<Card> deck) {
Random random = new Random(20190905);
for (int i = deck.size() - 1; i > 0; i--) {
int r = random.nextInt(i);
swap(deck, i, r);
}
}
public static void main(String[] args) {
List<Card> deck = buyDeck();
System.out.println("剛買回來的牌:");
System.out.println(deck);
shuffle(deck);
System.out.println("洗過的牌:");
System.out.println(deck);
// 三個人,每個人輪流抓 5 張牌
List<List<Card>> hands = new ArrayList<>();
hands.add(new ArrayList<>());
hands.add(new ArrayList<>());
hands.add(new ArrayList<>());
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 3; j++) {
hands.get(j).add(deck.remove(0));
}
}
System.out.println("剩余的牌:");
System.out.println(deck);
System.out.println("A 手中的牌:");
System.out.println(hands.get(0));
System.out.println("B 手中的牌:");
System.out.println(hands.get(1));
System.out.println("C 手中的牌:");
System.out.println(hands.get(2));
}
}
運行結(jié)果
剛買回來的牌:
[[♠ 1], [♠ 2], [♠ 3], [♠ 4], [♠ 5], [♠ 6], [♠ 7], [♠ 8], [♠ 9], [♠ 10], [♠ 11], [♠ 12], [♠ 13], [♥ 1], [♥ 2], [♥ 3], [♥ 4], [♥ 5], [♥ 6], [♥ 7],
[♥ 8], [♥ 9], [♥ 10], [♥ 11], [♥ 12], [♥ 13], [♣ 1], [♣ 2], [♣ 3], [♣ 4], [♣ 5], [♣ 6], [♣ 7], [♣ 8], [♣ 9], [♣ 10], [♣ 11], [♣ 12], [♣
13], [♦ 1], [♦ 2], [♦ 3], [♦ 4], [♦ 5], [♦ 6], [♦ 7], [♦ 8], [♦ 9], [♦ 10], [♦ 11], [♦ 12], [♦ 13]]
洗過的牌:
[[♥ 11], [♥ 6], [♣ 13], [♣ 10], [♥ 13], [♠ 2], [♦ 1], [♥ 9], [♥ 12], [♦ 5], [♥ 8], [♠ 6], [♠ 3], [♥ 5], [♥ 1], [♦ 6], [♦ 13], [♣ 12], [♦ 12],
[♣ 5], [♠ 4], [♣ 3], [♥ 7], [♦ 3], [♣ 2], [♠ 1], [♦ 2], [♥ 4], [♦ 8], [♠ 10], [♦ 11], [♥ 10], [♦ 7], [♣ 9], [♦ 4], [♣ 8], [♣ 7], [♠ 8], [♦ 9], [♠
12], [♠ 11], [♣ 11], [♦ 10], [♠ 5], [♠ 13], [♠ 9], [♠ 7], [♣ 6], [♣ 4], [♥ 2], [♣ 1], [♥ 3]]
剩余的牌:
[[♦ 6], [♦ 13], [♣ 12], [♦ 12], [♣ 5], [♠ 4], [♣ 3], [♥ 7], [♦ 3], [♣ 2], [♠ 1], [♦ 2], [♥ 4], [♦ 8], [♠ 10], [♦ 11], [♥ 10], [♦ 7], [♣ 9], [♦
4], [♣ 8], [♣ 7], [♠ 8], [♦ 9], [♠ 12], [♠ 11], [♣ 11], [♦ 10], [♠ 5], [♠ 13], [♠ 9], [♠ 7], [♣ 6], [♣ 4], [♥ 2], [♣ 1], [♥ 3]]
A 手中的牌:
[[♥ 11], [♣ 10], [♦ 1], [♦ 5], [♠ 3]]
B 手中的牌:
[[♥ 6], [♥ 13], [♥ 9], [♥ 8], [♥ 5]]
C 手中的牌:
[[♣ 13], [♠ 2], [♥ 12], [♠ 6], [♥ 1]]
到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之ArrayList從順序表到實現(xiàn)的文章就介紹到這了,更多相關(guān)Java ArrayList內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java KindEditor粘貼圖片自動上傳到服務(wù)器功能實現(xiàn)
這篇文章主要介紹了Java KindEditor粘貼圖片自動上傳到服務(wù)器功能實現(xiàn),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
SpringBoot攔截器與文件上傳實現(xiàn)方法與源碼分析
其實spring boot攔截器的配置方式和springMVC差不多,只有一些小的改變需要注意下就ok了。本文主要給大家介紹了關(guān)于如何在Springboot實現(xiàn)登陸攔截器與文件上傳功能,需要的朋友可以參考下2022-10-10
詳解Java圖形化編程中的鼠標(biāo)事件設(shè)計
這篇文章主要介紹了Java圖形化編程中的鼠標(biāo)事件設(shè)計,是Java的GUI開發(fā)中的基礎(chǔ)部分,需要的朋友可以參考下2015-10-10
springboot+vue2+elementui實現(xiàn)時間段查詢方法
這篇文章主要介紹了springboot+vue2+elementui實現(xiàn)時間段查詢方法,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-05-05
SpringBoot日志配置SLF4J和Logback的方法實現(xiàn)
日志記錄是不可或缺的一部分,本文主要介紹了SpringBoot日志配置SLF4J和Logback的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04

