Java集合框架之List ArrayList LinkedList使用詳解刨析
1. List
1.1 List 的常見方法
方法 | 描述 |
---|---|
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) |
獲取下標 index 位置的元素 |
E set(int index, E element) |
將下標 index 位置元素設置為 element |
void clear() |
清空 |
boolean contains(Object o) |
判斷 o 是否在線性表中 |
int indexOf(Object o) |
返回第一個 o 所在下標 |
int lastIndexOf(Object o) |
返回最後一個 o 的下標 |
List<E> subList(int fromIndex, int toIndex) |
截取部分 list |
1.2 代碼示例
註意: 下面的示例都是一份代碼分開拿出來的,上下其實是有邏輯關系的
示例一: 用 List 構造一個元素為整形的順序表
List<Integer> list = new ArrayList<>();
示例二: 尾插 e
list.add(1); list.add(2); System.out.println(list); // 結果為:[1, 2]
示例三: 將 e 插入到 index 位置
list.add(0,10); System.out.println(list); // 結果為:[10, 1, 2]
示例四: 尾插 c 中的元素
List<Integer> list1=new LinkedList<>(); list1.add(99); list1.add(100); list.addAll(list1); System.out.println(list); // 結果為:[10, 1, 2, 99, 100]
隻要是繼承於 Collection 的集合類的元素都可以被插入進去,但要註意傳過來的具體的類型要麼是和 list 的具體類型是一樣的,要麼是 list 具體類型的子類
示例五: 刪除 index 位置的元素
System.out.println(list.remove(0)); System.out.println(list); // 結果為:10 和 [1, 2, 99, 100]
示例六: 刪除遇到的第一個 o
System.out.println(list.remove((Integer) 100)); System.out.println(list); // 結果為:true 和 [1, 2, 99]
示例七: 獲取下標 index 位置的元素
System.out.println(list.get(0)); // 結果為:1
示例八: 將下標 index 位置元素設置為 element
System.out.println(list.set(2,3)); System.out.println(list); // 結果為:99 和 [1, 2, 3]
示例九: 判斷 o 是否在線性表中
System.out.println(list.contains(1)); // 結果為:true
示例十: 返回第一個 o 所在下標
System.out.println(list.indexOf(1)); // 結果為:0
示例十一: 返回最後一個 o 的下標
list.add(1); System.out.println(list.lastIndexOf(1)); // 結果為:3
示例十二: 截取部分 list
List<Integer> list2=list.subList(1,3); System.out.println(list2); // 結果為:[2, 3]
註意,當我們將 list2 通過 set 更改元素,其實對 list 也會有影響
list2.set(0,5); System.out.println(list2); System.out.println(list); // 結果為:[5, 3] 和 [1, 5, 3, 1]
通過 subList 方法進行的截取,得到的集合的數值指向的地址和原集合中數值的地址是一樣的
2. ArrayList
2.1 介紹
ArrayList 類是一個可以動態修改的數組,與普通數組的區別就是它是沒有固定大小的限制,我們可以添加或刪除元素。其繼承瞭 AbstractList,並實現瞭 List 接口。LinkedList 不僅實現瞭 List 接口,還實現瞭 Queue 和 Deque 接口,可以作為隊列去使用。
ArrayList 類位於 java.util
包中,使用前需要引入它。
2.2 ArrayList 的構造方法
方法 | 描述 |
---|---|
ArrayList() |
無參構造 |
ArrayList(Collection<? extends E> c) |
利用其他 Collection 構建 ArrayList |
ArrayList(int initialCapacity) |
指定順序表初始容量 |
示例一:
ArrayList<Integer> list1 = new ArrayList<>();
示例二:
ArrayList<Integer> list2 = new ArrayList<>(10); // 該構造方法就是在構建時就將底層數組大小設置為瞭10
示例三:
List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); ArrayList<Integer> list3 = new ArrayList<>(list);
Collection<? extends E> c
隻要是具體類型都和 list3 是一樣的集合都可以放入轉化成 ArrayList
2.3 ArrayList 底層數組的大小
當我們使用 add 方法給 ArrayList 的對象進行尾插時,突然想到瞭一個問題:既然 ArrayList 的底層是一個數組,那麼這個數組有多大呢?
為瞭解決這個問題,我進行瞭如下探索
跳轉到 ArrayList 的定義,我們看到瞭 elementData
和 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
跳轉到 elementData
的定義,我們可以瞭解 ArrayList 底層是數組的原因
跳轉到 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
的定義,初步分析得到這個數組其實是空的
為什麼這個數組是空的但存儲元素的時候沒有報異常呢?我們再去瞭解下 add 是怎樣存儲的
通過轉到 ArrayList 的 add 方法的定義
通過定義,不難發現,數組容量和 ensureCapacityInternal
這個東西有關,那我們就看看它的定義
我們看裡面的 calculateCapacity
,他有兩個參數,此時數組為空,那麼 minCapacity
就為 1。我們再轉到 calculateCapacity
看看它的定義
此時我們就好像可以與之前串起來瞭,當數組為 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
時,就返回 DeFauLt_CAPACITY
和 minCapacity
(此時為1) 的最大值。DeFauLt_CAPACITY
其實是默認容量的意思,我們可以轉到它的定義看看有多大
DeFauLt_CAPACITY
的值是10,故 calculateCapacity
函數此時的返回值為10,最後我們再確定一下 ensureExplicitCapacity
是幹啥的
此時 minCapacity 的值是10,而數組為空時數組長度為0,所以進入 if 語句,執行 grow 方法,我們繼續轉到 grow 的定義
此時我們就可以瞭解,當我們創建一個 ArrayList 時,其底層數組大小其實是0。當我們第一次 add 的時候,經過 grow ,數組的大小就被擴容為瞭10。並且這大小為10的容量放滿以後,就會按1.5倍的大小繼續擴容。至於這個數組最大能存放多少,大傢可以再轉到 MAX_ARRAY_SIZE
的定義去查看。
3. LinkedList
3.1 介紹
LinkedList 類是一種常見的基礎數據結構,是一種線性表,但是並不會按線性的順序存儲數據,而是在每一個節點裡存到下一個節點的地址。
Java 的 LinkedList 底層是一個雙向鏈表,位於 java.util
包中,使用前需要引入它
3.2 LinkedList 的構造方法
方法 | 描述 |
---|---|
LinkedList() |
無參構造 |
LinkedList(Collection<? extends E> c) |
利用其他 Collection 構建 LinkedList |
示例一:
LinkedList<Integer> list1 = new LinkedList<>();
示例二:
List<Integer> list = new LinkedList<>(); list.add(1); list.add(2); LinkedList<Integer> list2 = new LinkedList<>(list);
Collection<? extends E> c
隻要是具體類型都和 list2 是一樣的集合都可以放入轉化成 LinkedList
4. 練習題
習題一
題目描述:
霍格沃茨學院有若幹學生(學生對象放在一個 List 中),每個學生有一個姓名(String)、班級(String)和考試成績(double)。某次考試結束後,每個學生都獲得瞭一個考試成績。遍歷 list 集合,並把每個學生對象的屬性都打印出來
本題代碼:
class Student{ private String name; private String classes; private double score; // 重寫構造方法 public Student(String name, String classes, double score) { this.name = name; this.classes = classes; this.score = score; } // 構造 get 和 set 方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClasses() { return classes; } public void setClasses(String classes) { this.classes = classes; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } // 重寫 toString 方法 @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", classes='" + classes + '\'' + ", score=" + score + '}'; } } public class TestDemo { public static void main(String[] args) { ArrayList<Student> students = new ArrayList<>(); students.add(new Student("哈利波特","大二班",95.5)); students.add(new Student("赫敏格蘭傑","小三班",93)); students.add(new Student("羅恩韋斯萊","小二班",91)); for(Student s: students){ System.out.println(s); } } } // 結果為: // Student{name='哈利波特', classes='大二班', score=95.5} // Student{name='赫敏格蘭傑', classes='小三班', score=93.0} // Student{name='羅恩韋斯萊', classes='小二班', score=91.0}
習題二
題目描述:
有一個 List 當中存放的是整形的數據,要求使用 Collections.sort
對 List 進行排序
該題代碼:
public class TestDemo { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(3); list.add(7); list.add(1); list.add(6); list.add(2); Collections.sort(list); System.out.println(list); } } // 結果為:[1, 2, 3, 6, 7]
補充:
Collections 是一個工具類,sort 是其中的靜態方法,它是用來對 List 類型進行排序的
註意:
如果具體的類是類似於習題一那樣的 Student 類,該類中含有多個屬性,那就不能直接使用這個方法。要對 comparator
或者 comparable
接口進行重寫,確定比較的是哪個屬性才行
習題三
題目描述:
輸出刪除瞭第一個字符串當中出現的第二個字符串中的字符的字符串,例如
String str1 = "welcome to harrypotter"; String str2 = "come"; // 結果為:wl t harrypttr
希望本題可以使用集合來解決
該題代碼:
public static void removeS(String str1, String str2){ if(str1==null || str2==null){ return; } List<Character> list = new ArrayList<>(); int lenStr1=str1.length(); for(int i=0; i<lenStr1; i++){ char c = str1.charAt(i); if(!str2.contains(c+"")){ list.add(c); } } for(char ch: list){ System.out.print(ch); } }
5. 撲克牌小遊戲
我們可以通過上述所學,運用 List 的知識,去寫一個關於撲克牌的邏輯代碼(如:獲取一副牌、洗牌、發牌等等)
class Card{ private String suit; // 花色 private int rank; // 牌面值 public Card(String suit, int rank){ this.suit=suit; this.rank=rank; } @Override public String toString() { return "[ "+suit+" "+rank+" ] "; } } public class TestDemo { public static String[] suits = {"♣", "♦", "♥", "♠"}; // 獲取一副牌 public static List<Card> getNewCards(){ // 存放 52 張牌 List<Card> card = new ArrayList<>(); for(int i=0; i<4; i++){ for(int j=1; j<=13; j++) { card.add(new Card(suits[i], j)); } } return card; } public static void swap(List<Card> card, int i, int j){ Card tmp = card.get(i); card.set(i, card.get(j)); card.set(j, tmp); } // 洗牌 public static void shuffle(List<Card> card){ int size = card.size(); for(int i=size-1; i>0; i--){ Random random = new Random(); int randNum = random.nextInt(i); swap(card, i, randNum); } } public static void main(String[] args) { // 得到一副新的牌 List<Card> cardList = getNewCards(); System.out.println("已獲取新的撲克牌"); System.out.println("洗牌:"); shuffle(cardList); System.out.println(cardList); System.out.println("抓牌:(3個人,每人輪流抓牌總共抓5張)"); List<Card> hand1 = new ArrayList<>(); List<Card> hand2 = new ArrayList<>(); List<Card> hand3 = new ArrayList<>(); List<List<Card>> hands = new ArrayList<>(); hands.add(hand1); hands.add(hand2); hands.add(hand3); for(int i=0; i<5; i++){ for(int j=0; j<3; j++){ Card card = cardList.remove(0); hands.get(j).add(card); } } System.out.println("第一個人的牌:"+hand1); System.out.println("第二個人的牌:"+hand2); System.out.println("第三個人的牌:"+hand3); } } /** 結果為: 已獲取新的撲克牌 洗牌: [[ ♥ 9 ] , [ ♦ 6 ] , [ ♣ 8 ] , [ ♦ 2 ] , [ ♣ 6 ] , [ ♦ 4 ] , [ ♣ 11 ] , [ ♣ 9 ] , [ ♠ 8 ] , [ ♣ 5 ] , [ ♦ 8 ] , [ ♦ 10 ] , [ ♦ 1 ] , [ ♦ 12 ] , [ ♥ 10 ] , [ ♥ 7 ] , [ ♠ 12 ] , [ ♥ 12 ] , [ ♦ 7 ] , [ ♣ 13 ] , [ ♠ 6 ] , [ ♠ 5 ] , [ ♥ 3 ] , [ ♦ 5 ] , [ ♦ 11 ] , [ ♣ 12 ] , [ ♠ 7 ] , [ ♦ 3 ] , [ ♥ 5 ] , [ ♦ 13 ] , [ ♣ 1 ] , [ ♥ 8 ] , [ ♠ 10 ] , [ ♠ 4 ] , [ ♣ 4 ] , [ ♣ 7 ] , [ ♥ 1 ] , [ ♠ 1 ] , [ ♣ 3 ] , [ ♥ 11 ] , [ ♥ 13 ] , [ ♦ 9 ] , [ ♠ 13 ] , [ ♣ 10 ] , [ ♥ 6 ] , [ ♠ 11 ] , [ ♠ 3 ] , [ ♣ 2 ] , [ ♠ 2 ] , [ ♥ 2 ] , [ ♥ 4 ] , [ ♠ 9 ] ] 抓牌:(3個人,每人輪流抓牌總共抓5張) 第一個人的牌:[[ ♥ 9 ] , [ ♦ 2 ] , [ ♣ 11 ] , [ ♣ 5 ] , [ ♦ 1 ] ] 第二個人的牌:[[ ♦ 6 ] , [ ♣ 6 ] , [ ♣ 9 ] , [ ♦ 8 ] , [ ♦ 12 ] ] 第三個人的牌:[[ ♣ 8 ] , [ ♦ 4 ] , [ ♠ 8 ] , [ ♦ 10 ] , [ ♥ 10 ] ] */
上述代碼中有一處代碼是這樣寫的 List<List<Card>>
,其實不難理解,這個類型其實就是 List 中存放的每個元素都是一個 List 類型的,並且每一個 List 元素中的元素都是 Card 類型,類似於二維數組。
以上就是Java集合框架之List ArrayList LinkedList使用詳解刨析的詳細內容,更多關於Java 集合框架的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Java使用ArrayList實現撲克牌的示例代碼
- Java List接口的集合使用詳解
- 簡單闡述一下Java集合的概要
- 一文掌握Java中List和Set接口的基本使用
- Java ArrayList中存放引用數據類型的方式