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

說明:
- ArrayList實(shí)現(xiàn)了RandomAccess接口,表明ArrayList支持隨機(jī)訪問
- ArrayList實(shí)現(xiàn)了Cloneable接口,表明ArrayList是可以clone的
- ArrayList實(shí)現(xiàn)了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是線程安全的,在單線程下可以使用,在多線程中可以選擇Vector或者CopyOnWriteArrayList
- ArrayList底層是一段連續(xù)的空間,并且可以動(dòng)態(tài)擴(kuò)容,是一個(gè)動(dòng)態(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)造一個(gè)空的列表
List<Integer> list1 = new ArrayList<>();
// 構(gòu)造一個(gè)具有10個(gè)容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 編譯失敗,List<Integer>已經(jīng)限定了,list2中只能存儲(chǔ)整形元素
// list3構(gòu)造好之后,與list中的元素一致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略類型,否則:任意類型的元素都可以存放,使用時(shí)將是一場(chǎng)災(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) | 刪除遇到的第一個(gè) 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) | 返回第一個(gè) o 所在下標(biāo) |
| int lastIndexOf(Object o) | 返回最后一個(gè) 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("測(cè)試課程");
System.out.println(list);
// 獲取list中有效元素個(gè)數(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)一往后搬移一個(gè)位置
list.add(1, "Java數(shù)據(jù)結(jié)構(gòu)");
System.out.println(list);
// 刪除指定元素,找到了就刪除,該元素之后的元素統(tǒng)一往前搬移一個(gè)位置
list.remove("JVM");
System.out.println(list);
// 刪除list中index位置上的元素,注意index不要超過list中有效元素個(gè)數(shù),否則會(huì)拋出下標(biāo)越界異常
list.remove(list.size()-1);
System.out.println(list);
//輸出結(jié)果:
[JavaSE, JavaWeb, JavaEE, JVM, 測(cè)試課程]
5
JavaWeb
JavaWEB
[JavaSE, Java數(shù)據(jù)結(jié)構(gòu), JavaWEB, JavaEE, JVM, 測(cè)試課程]
[JavaSE, Java數(shù)據(jù)結(jié)構(gòu), JavaWEB, JavaEE, 測(cè)試課程]
[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的擴(kuò)容機(jī)制
ArrayList是一個(gè)動(dòng)態(tài)類型的順序表,即:在插入元素的過程中會(huì)自動(dòng)擴(kuò)容:以下是ArrayList源碼中擴(kuò)容方式
Object[] elementData; // 存放元素的空間
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默認(rèn)空間
private static final int DEFAULT_CAPACITY = 10; // 默認(rèn)容量大小
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ù)計(jì)按照1.5倍方式擴(kuò)容
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用戶需要擴(kuò)容大小 超過 原空間1.5倍,按照用戶所需大小擴(kuò)容
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果需要擴(kuò)容大小超過MAX_ARRAY_SIZE,重新計(jì)算容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 調(diào)用copyOf擴(kuò)容
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;
}
檢測(cè)是否真正需要擴(kuò)容,如果是調(diào)用grow準(zhǔn)備擴(kuò)容
預(yù)估需要庫容的大小
- 初步預(yù)估按照1.5倍大小擴(kuò)容
- 如果用戶所需大小超過預(yù)估1.5倍大小,則按照用戶所需大小擴(kuò)容
- 真正擴(kuò)容之前檢測(cè)是否能擴(kuò)容成功,防止太大導(dǎo)致擴(kuò)容失敗
使用copyOf進(jìn)行擴(kuò)容
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);
// 三個(gè)人,每個(gè)人輪流抓 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));
}
}
運(yùn)行結(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從順序表到實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java ArrayList內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java KindEditor粘貼圖片自動(dòng)上傳到服務(wù)器功能實(shí)現(xiàn)
這篇文章主要介紹了Java KindEditor粘貼圖片自動(dòng)上傳到服務(wù)器功能實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
SpringBoot攔截器與文件上傳實(shí)現(xiàn)方法與源碼分析
其實(shí)spring boot攔截器的配置方式和springMVC差不多,只有一些小的改變需要注意下就ok了。本文主要給大家介紹了關(guān)于如何在Springboot實(shí)現(xiàn)登陸攔截器與文件上傳功能,需要的朋友可以參考下2022-10-10
詳解Java圖形化編程中的鼠標(biāo)事件設(shè)計(jì)
這篇文章主要介紹了Java圖形化編程中的鼠標(biāo)事件設(shè)計(jì),是Java的GUI開發(fā)中的基礎(chǔ)部分,需要的朋友可以參考下2015-10-10
springboot+vue2+elementui實(shí)現(xiàn)時(shí)間段查詢方法
這篇文章主要介紹了springboot+vue2+elementui實(shí)現(xiàn)時(shí)間段查詢方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-05-05
Java實(shí)現(xiàn)遞歸刪除菜單和目錄及目錄下所有文件
這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)遞歸刪除菜單和刪除目錄及目錄下所有文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2025-03-03
SpringBoot日志配置SLF4J和Logback的方法實(shí)現(xiàn)
日志記錄是不可或缺的一部分,本文主要介紹了SpringBoot日志配置SLF4J和Logback的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04

