宣告:博主gitee內附Java學習筆記
文章前言:
那么集合框架就是 Java 寫好的一些資料結構,像是順序表,鏈表,堆疊和佇列……這些資料結構不需要我們去手動的進行實作,我們要做的就是去了解一下每個集合框架背后的資料結構,那么我們今天就去了解一下List介面中的ArrayList
文章目錄:
1、預備知識----泛型
2、預備知識----包裝類
3、正式開始---- ArrayList與順序表
4、模擬底層實作ArrayList
5、ArrayList實戰模擬實作撲克牌

1、預備知識----泛型
宣告:在這里的泛型了解為主,后面會有專門的博客去解釋泛型,這里只是簡單的預備知識,以看得懂原碼為主要目的
以上的代碼會引發一定的問題:
由于使用泛型 E/T 不可以實體化陣列,這里先提供一個可以使用,但不完全正確的寫法,我們先看泛型使用的結果
由此我們開始探索泛型的意義:
正確書寫代碼需要使用到反射的知識,后面有專門的博客進行講解,這里知道需要使用反射表示即可
2、預備知識----包裝類
Java引入的一種特殊的類,即 8 種基本型別的包裝類

注意:不是所有類都有包裝類,包裝類主要針對的是 8 種基本資料型別
初識包裝類
那么有基本資料型別,為什么還需要有包裝類?
使用包裝類實作上述問題:
我們發現使用包裝類去實作轉換功能十分的簡單,省去撰寫一個方法去實作轉換的操作
所以,包裝類的好處:
裝包(裝箱)與拆包(拆箱)
宣告:利用 (Javap -c 檔案名) 指令即可查看匯編代碼
①、裝包(裝箱)
②、拆包(拆箱)
所以裝箱和拆箱在底層是會幫助我們去做一些東西
那么顯示的拆箱和裝箱又是怎么樣的呢
①、顯示的裝箱
由于 Integer 是一個類(包裝類),所以顯示的裝箱也可以這樣寫:
②、顯示的拆箱
相關的一道阿里面試題:
相同的數值為什么會存在兩個結果 ?常規來說兩個數值一致應該都會回傳 true
所以把 valueOf 這個方法作為問題的一個切入點,Ctrl + 點擊 valueOf 查看其原碼
分析原碼:
計算 cache 陣列 范圍:
所以數值在 [-128 ~ 127] 范圍內就會直接回傳陣列中的該數值,不在范圍內會實體化一個新的物件
所以:
第一種情況 a 和 b 是相同的,因為沒有實體化新的物件,從快取陣列中取出來直接賦值給 a 和 b
第二種情況 a 和 b 不相同的,因為 129 超過范圍實體化兩個完全不同的物件,所以在比較的時候 a 和 b 是不相同的
3、正式開始---- ArrayList與順序表

ArrayList簡介:
在集合框架中,ArrayList是一個普通的類,實作了List介面,具體框架圖如下:
ArrayList的使用:
①、實體化一個ArryaList
②、向 ArrayList 中添加資料(由于 ArrayList 重寫了 toString 方法所以可以直接列印 list 即可)
回圈遍歷順序表:
由于 ArrayList 實作了 Iterable 介面所以可以使用增強 for 回圈進行列印
還可以使用迭代器進行列印
第二種針對于 List 的迭代器
有關 ListIterator 和 Iterator 的詳解
宣告:該內容參考博客
①、Iterator 介面
forEachRemaining(Consumer<? super E> action) 為每個剩余元素執行給定的操作,直到所有的元素都已經被處理或行動將拋出一個例外
hasNext(): 如果迭代器中還有元素,則回傳true,
next(): 回傳迭代器中的下一個元素
remove(): 洗掉迭代器新回傳的元素,
在使用 remove 方法的時候,一定注意要先把元素全部迭代出來后,再進行操作,否則會引發例外
注意:
- Iterator只能單向移動,
- Iterator.remove()是唯一安全的方式來在迭代程序中修改集合;如果在迭代程序中以任何其它的方式修改了基本集合將會產生未知的行為,而且每呼叫一次next()方法,remove()方法只能被呼叫一次,如果違反這個規則將拋出一個例外,
②、ListIterator介面
ListIterator是一個功能更加強大的, 它繼承于Iterator介面,只能用于各種List型別的訪問,可以通過呼叫listIterator()方法產生一個指向List開始處的ListIterator, 還可以呼叫listIterator(n)方法創建一個一開始就指向串列索引為n的元素處的ListIterator,
ListIterator介面可以實作的功能:
- 雙向移動(向前 / 向后遍歷)
- 產生相對于迭代器在串列中指向的當前位置的前一個和后一個元素的索引.
- 可以使用set()方法替換它訪問過的最后一個元素.
- 可以使用add()方法在next()方法回傳的元素之前或previous()方法回傳的元素之后插入一個元素.
使用實體:(remove方法和上面介紹的使用方法一致)
兩個介面之間的區別:
- ListIterator有add()方法,可以向List中添加物件,而Iterator不能
- ListIterator和Iterator都有hasNext()和next()方法,可以實作順序向后遍歷,但是ListIterator有hasPrevious()和previous()方法,可以實作逆向(順序向前)遍歷,Iterator就不可以,
- ListIterator可以定位當前的索引位置,nextIndex()和previousIndex()可以實作,Iterator沒有此功能,
- 都可實作洗掉物件,但是ListIterator可以實作物件的修改,set()方法可以實作,Iierator僅能遍歷,不能修改
有關執行緒安全問題:
ArrayList 可實作的功能
①、插入元素
②、在某個位置插入元素
③、洗掉指定位置的元素
④、洗掉指定物件
⑤、獲取指定下標位置的元素
⑥、更新指定下標位置的元素
⑦、清空順序表
⑧、在順序表中查找對應元素是否存在
⑨、查找元素在順序表中的下標位置
⑩、按照給定下標范圍分割順序表
看一個問題:如果改變分割后的順序表會影響到原來的順序表嗎
觀察一個代碼的有無問題
那大小為:0 的時候為什么也可以向順序表中添加元素,那我們看一下 add 方法的源代碼解決此問題
4、模擬底層實作ArrayList
搭建順序表框架(參照源代碼)
實作順序表的操作(只實作前兩個看得懂即可):
1、表尾添加資料
2、指定位置添加元素
5、ArrayList實戰模擬實作撲克牌


1、搭建撲克牌框架(花色+大小)
2、提供合適的構造方法
3、花色和大小初始化的 Get Set 方法,可以供其他使用
4、重寫 toString 方法方便一會列印花色和大小
撲克牌的基本框架搭建好后,進行玩牌三步走:
步驟一、買一副撲克牌(忽略大小王)
步驟二、買來的牌都是連著花色和大小的,所以我們需要進行洗牌
步驟三、洗好的牌,最后一步就是發到每個人的手中
整體代碼:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2022-01-05
* Time: 13:49
*/
class Card{
private int sank;
private String suit;
public Card(int sank, String suit) {
this.sank = sank;
this.suit = suit;
}
public int getSank() {
return sank;
}
public void setSank(int sank) {
this.sank = sank;
}
public String getSuit() {
return suit;
}
public void setSuit(String suit) {
this.suit = suit;
}
@Override
public String toString() {
return "["+this.suit+" "+this.sank+"]";
}
}
public class Test3 {
private static final String[] suits = {"?","?","?","?"};
private static List<Card> buyCard(){
ArrayList<Card> list = new ArrayList<>();
for (int i = 0; i < 4; i++) {
for (int j = 1; j <= 13; j++) {
list.add(new Card(j,suits[i]));
}
}
return list;
}
private static void swap(List<Card> cards, int i, int j){
Card tmp = cards.get(i);
cards.set(i, cards.get(j));
cards.set(j,tmp);
}
private static void shuffle(List<Card> cards){
int size = cards.size();
for (int i = size - 1; i > 0 ; i--) {
Random rd = new Random();
int rand = rd.nextInt(i);
swap(cards,i,rand);
}
}
private static void sendCards(List<Card> cards){
ArrayList<List<Card>> hand = new ArrayList<>();
List<Card> hand1 = new ArrayList<>();
List<Card> hand2 = new ArrayList<>();
List<Card> hand3 = new ArrayList<>();
hand.add(hand1);
hand.add(hand2);
hand.add(hand3);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 3; j++) {
Card card = cards.remove(0);
hand.get(j).add(card);
}
}
System.out.println("第一個人牌:"+hand1);
System.out.println("第二個人牌:"+hand2);
System.out.println("第三個人牌:"+hand3);
System.out.println("剩余的牌"+cards);
}
public static void main(String[] args) {
List<Card> cards = buyCard();
//買牌
System.out.println("買牌:"+cards);
//洗牌
shuffle(cards);
System.out.println("洗牌:"+cards);
//發牌
sendCards(cards);
}
}
本章結束
有任何問題隨時聯系博主,盡全力解決,感謝支持!!!!!!
??????????????????????????????????????????????????????????????????????????????????
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/404132.html
標籤:其他
下一篇:GDB除錯-從入門實踐到原理











































































