JavaSE第15篇:集合之Collection集合上篇
核心概述:在之前的篇章中,我們學習了陣列,因為陣列本身資料結構的侷限性,對於陣列內元素除查詢操作外的其他操作(增刪改)比較低效,所以,我們又學習了集合ArrayList,初步體驗了集合操作的便捷性。本篇我們將開始系統地學習Java中的集合體系。
目錄
第一章:物件陣列
陣列是容器,即可以儲存基本資料型別也可以引用資料型別,儲存了引用資料型別的陣列稱為物件陣列,例如:String[],Person[],Student[]。
public static void main(String[] args){ //建立儲存Person物件的陣列 Person[] persons = { new Person("張三",20), new Person("李四",21), new Person("王五",22), }; //遍歷陣列 for(int i = 0 ; i < persons.length; i++){ Person person = persons[i]; System.out.println(person.getName()+"::"+person.getAge()); } }
陣列的弊端:
- 陣列長度是固定的,一旦建立不可修改。
- 需要新增元素,只能建立新的陣列,將原陣列中的元素進行復制。
為了解決陣列的定長問題,Java語言從JDK1.2開始出現集合框架。
第二章:認識集合
1.1-集合概述(瞭解)
在之前的篇章中我們已經學習過並使用過集合ArrayList<E>
,那麼集合到底是什麼呢?
簡而言之,集合就是是java中提供的一種容器,可以用來儲存多個數據。
這麼說,集合和陣列非常相似,就是儲存多個數據的容器。那麼,集合和陣列有什麼區別呢?
- 陣列的長度是固定的。集合的長度是可變的。
- 陣列中儲存的是同一型別的元素,可以儲存任意型別資料。集合儲存的都是引用資料型別。如果想儲存基本型別資料需要儲存對應的包裝型別。
1.2-Java中的集合框架(瞭解)
以下的集合體系描述,不是所有的集合,而是常用的集合。
單列集合體系
雙列集合體系
由於集合體系豐富,我們將會分多個篇幅學習,本篇我們將學習單列集合體系Collection中的List系列集合。
1.3-Collection集合通用方法(記憶)
Collection是所有單列集合的父介面,因此在Collection中定義了單列集合(List和Set)通用的一些方法,這些方法可用於操作所有的單列集合。方法如下:
public boolean add(E e)
: 把給定的物件新增到當前集合中 。public boolean addAll(Collection<? extends E>)
將另一個集合元素新增到當前集合中。public void clear()
:清空集合中所有的元素。public boolean remove(E e)
: 把給定的物件在當前集合中刪除。public boolean contains(Object obj)
: 判斷當前集合中是否包含給定的物件。public boolean isEmpty()
: 判斷當前集合是否為空。public int size()
: 返回集合中元素的個數。public Object[] toArray()
: 把集合中的元素,儲存到陣列中。
程式碼示例
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
// 新增元素
list.add("張三");
list.add("李四");
Collection<String> list2 = new ArrayList<>();
list2.add("王五");
list2.add("趙六");
// 將list2集合元素新增到list集合中
list.addAll(list2);
System.out.println(list);
// 移除元素
list.remove("張三");
System.out.println(list);
// 判斷集合中是否包含某個元素
boolean isHas = list.contains("張三");
System.out.println(isHas); // false
// 判斷當前集合是否為空
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
// 清空元素
list.clear();
System.out.println(list);
// 集合的長度
System.out.println(list.size());
// 集合中的元素儲存到一個數組中
Object[]s = list.toArray();
}
}
第三章:遍歷集合
3.1-Iterator方式遍歷(記憶)
介紹
Iterator,是一個迭代器介面。Collection中的成員方法iterator()
被呼叫後,會返回一個Iterator物件。利用這個物件可以實現遍歷集合。如何遍歷呢?在取元素之前先要判斷集合中有沒有元素,如果有,就把這個元素取出來,繼續在判斷,如果還有就再取出出來。一直把集合中的所有元素全部取出。這種取出方式專業術語稱為迭代。
Iterator物件的成員方法:
- hasNext(); 檢測集合中是否存在下一個元素
- next(); 找到並獲取下一個元素
示例程式碼:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("張三");
list.add("李四");
list.add("王五");
// 得到一個迭代器物件
Iterator<String> it = list.iterator();
// 判斷集合中是否還有元素
while (it.hasNext()) {
// 取出元素
String str = it.next();
System.out.println(str);
}
}
}
迭代器執行過程
在呼叫Iterator的next方法之前,迭代器的索引位於第一個元素之前,不指向任何元素,當第一次呼叫迭代器的next方法後,迭代器的索引會向後移動一位,指向第一個元素並將該元素返回,當再次呼叫next方法時,迭代器的索引會指向第二個元素並將該元素返回,依此類推,直到hasNext方法返回false,表示到達了集合的末尾,終止對元素的遍歷。
迭代器原始碼分析
迭代器是遍歷Collection集合的通用方式,任意Collection集合都可以使用迭代器進行遍歷,那麼每一種集合的自身特性是不同的,也就是儲存元素的方式不同,那麼是如何做到遍歷方式的統一呢,接下來我們分析一下迭代器的原始碼。
每個Collection集合都會實現,方法 Iterator iterator()
,返回Iterator介面實現類,以ArrayList集合為例
java.util.Iterator
介面:
public interface Iterator<E> {
boolean hasNext();
E next();
}
java.util.ArrayList
類:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
/*
* ArrayList實現介面Collection
* 重寫方法iterator()
* 返回Iterator介面實現類 Itr類的物件
*/
public Iterator<E> iterator() {
return new Itr();
}
/*
* ArrayList中定義內部類Itr,實現介面Iterator
* 重寫hasNext(),next()方法
*/
private class Itr implements Iterator<E> {
public boolean hasNext() {
// ...
}
public E next() {
// ...
}
}
所以結論是:
- 所有集合的迭代器,全由內部類實現。
- 集合中定義內部類,實現迭代器介面,可以使所有集合的遍歷方式統一。
- 呼叫迭代器的方法hasNext(),next()均執行集合中內部類的重寫方法。
併發修改異常
在使用迭代器遍歷集合中,不能使用集合本身的方法改變集合的長度,一旦被改變將會丟擲ConcurrentModificationException併發修改異常。
public static void main(String[] args){
Collection<String> coll = new ArrayList<String>();
coll.add("hello1");
coll.add("hello2");
coll.add("hello3");
coll.add("hello4");
Iterator<String> it = coll.iterator();
while (it.hasNext()){
String str = it.next();
if("hello2".equals(str)){
coll.add("hello5");
}
}
以上程式,在迭代器遍歷過程中,使用了集合add方法修改集合的長度,這個操作是不允許的,被禁止的,程式中會丟擲併發修改異常。
3.2-增強for方式遍歷(記憶)
概述
增強for迴圈(也稱for each迴圈)是JDK1.5以後出來的一個高階for迴圈,專門用來遍歷陣列和集合的。它的內部原理其實是個Iterator迭代器,所以在遍歷的過程中,不能對集合中的元素進行增刪操作。
語法格式
for(元素的資料型別 變數 : Collection集合or陣列){
//寫操作程式碼
}
變數,表示取出的某一個元素
程式碼示例:
import java.util.ArrayList;
import java.util.Collection;
public class Test {
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("張三");
list.add("李四");
list.add("王五");
for (String s : list) {
System.out.println(s);
}
}
}
/*
輸出結果:
張三
李四
王五
*/
第四章:資料結構
4.1-概述(瞭解)
資料結構就是計算機儲存、組織資料的方式 。
指的是相互之間存在著特定關係的一種或多種的資料元素集合。
為什麼要學習資料結構呢?
通常情況下,精心選擇合適的資料結構可以帶來更高的執行或儲存的效率。
比如:為什麼陣列查詢速度快,增刪改效率較低?為什麼有的集合更適合用於查詢,有的更適合用於增刪改?
4.2-資料結構-棧(瞭解)
介紹
棧:棧(stack)又名堆疊,是一種運算受限的線性表。
受限:限定僅在表尾進行插入和刪除操作的線性表(這一端被稱為棧頂,另一端稱為棧底)
這裡兩個名詞需要注意:
- 壓棧(入棧):就是存元素。即,把元素儲存到棧的頂端位置,棧中已有元素依次向棧底方向移動一個位置。
- 彈棧(出棧):就是取元素。即,把棧的頂端位置元素取出,棧中已有元素依次向棧頂方向移動一個位置。
特性
先進後出,是棧結構的特點。
4.3-資料結構-佇列(瞭解)
介紹
佇列:是一種受限的特殊線性表。
受限:只允許在表的前端(隊頭)進行刪除操作,後端(隊尾)進行插入操作。
特性
先進先出,是佇列資料結構的特點。
4.4-資料結構-陣列(瞭解)
介紹
陣列:一組有序的(索引有序並且從0開始)型別相同的長度固定的元素集合。
特性
- 元素有序
- 元素同類型
- 長度固定
應用效果
查詢快,從陣列索引0開始查詢,根據指定位置的偏移量可快速獲取資料。
增刪慢,陣列的長度是固定的,若刪除或增加一格元素,則會先建立一個新的陣列,再把原陣列的資料根據操作複製到新陣列中。
4.5-資料結構-連結串列(瞭解)
連結串列
連結串列:linked list,由一系列結點node(連結串列中每一個元素稱為結點)組成,結點可以在執行時動態生成。每個結點包括兩個部分:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域。我們常說的連結串列結構有單向連結串列與雙向連結串列,那麼這裡給大家介紹的是單向連結串列。
特性
- 多個結點之間,通過地址進行連線。例如,多個人手拉手,每個人使用自己的右手拉住下個人的左手,依次類推,這樣多個人就連在一起了。
- 結點可以在執行時動態生成。
- 每個結點包括兩個部分(單鏈表)
- 一個是儲存資料元素的資料域
- 另一個是儲存下一個結點地址的指標域。
應用效果
查詢慢
:連結串列的地址不是連續的,每次查詢都得從頭開始查詢。增刪快
:增刪操作不會影響連結串列的整體結構。
第五章:List集合
5.1-概述(瞭解)
概述
java.util.List
介面,繼承Collection介面,有序的 collection(也稱為序列)。此介面的使用者可以對列表中每個元素的插入位置進行精確地控制。使用者可以根據元素的整數索引(在列表中的位置)訪問元素,並搜尋列表中的元素。與Set介面不同,List介面通常允許重複元素。
特點
- List集合是有序的集合,儲存和取出的順序一致。
- List集合允許儲存重複的元素。
- List集合中的每個元素具有索引。
集合類名字尾是List,例如ArrayList,LinkedList等,都是List介面實現類,都具有List介面的特點。
5.2-List集合常用方法(記憶)
List作為Collection集合的子介面,不但繼承了Collection介面中的全部方法,而且還增加了一些根據元素索引來操 作集合的特有方法,如下:
方法:
public void add(int index, E element)
: 將指定的元素,新增到該集合中的指定位置上。public E get(int index)
:返回集合中指定位置的元素。public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。public E set(int index, E element)
:用指定元素替換集合中指定位置的元素,返回值的更新前的元素
程式碼:
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
// public void add(int index, E element) : 將指定的元素,新增到該集合中的指定位置上。
list.add(1,"d");
System.out.println(list); // [a, d, b, c]
// public E get(int index) :返回集合中指定位置的元素。
System.out.println(list.get(2)); // b
// public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
list.remove(1);
System.out.println(list); // [a, b, c]
// public E set(int index, E element) :用指定元素替換集合中指定位置的元素,返回值的更新前的元素
list.set(1,"B");
System.out.println(list); // [a, B, c]
第六章:ArrayList集合
6.1-概述(瞭解)
java.util.ArrayList
集合資料儲存的結構是陣列結構。元素增刪慢,查詢快,執行緒不安全,執行速度快。由於日常開發中使用最多的功能為查詢資料、遍歷資料,所以ArrayList
是最常用的集合。
許多程式設計師開發時非常隨意地使用ArrayList完成任何需求,並不嚴謹,這種用法是不提倡的。
6.2-ArrayList原始碼分析(瞭解)
底層就是陣列
底層是Object物件陣列,陣列儲存的資料型別是Object,陣列名字為elementData。
ArrayList類中部分原始碼
transient Object[] elementData;
建立ArrayList物件分析:無引數
初始化ArrayList物件,建立一個為10的空列表。也可以指定列表長度,構造方法傳遞長度即可。
new ArrayList(); //預設長度為10
new ArrayList(int initialCapacity); //指定長度
ArrayList無引數構造方法分析:
// 定義Object物件型別的空陣列,陣列在記憶體中存在,但長度為0
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
解析:這裡可以看出,當我們new ArrayList()的時候,並沒有建立長度為10的陣列,而是建立了一個長度為0的陣列,當我們使用add()方法新增元素的時候,就會將陣列由0長度,擴容為10長度。
ArrayList新增元素add方法分析:
//ArrayList的成員變數size,預設為0,統計集合中元素的個數
private int size;
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
解析:集合新增元素之前,先呼叫方法ensureCapacityInternal()增加容量,傳遞size+1,size預設為0。傳遞引數0+1的結果。
ensureCapacityInternal()增加容量方法分析:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
解析:方法ensureCapacityInternal()接收到引數1,繼續呼叫方法calculateCapacity()計算容量,傳遞陣列和1。
calculateCapacity()計算容量方法分析:
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
解析:方法中判斷elementData是否和DEFAULTCAPACITY_EMPTY_ELEMENTDATA陣列相等,在構造方法中:this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;因此結果為true,方法將會返回引數DEFAULT_CAPACITY(=10)和 minCapacity(=1)中最大的值,return 10;此時方法calculateCapacity()結束,繼續執行() ensureExplicitCapacity(),傳遞引數10
ensureExplicitCapacity()保證明確容量方法分析:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
解析:方法中進行判斷(10-elemetData.length>0)結果為true,10-0>0。呼叫方法grow()傳遞10。
grow()增加容量方法分析:
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
//**將10賦值給變數newCapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//**陣列複製, Arrays.copyOf底層實現是System.arrayCopy()
elementData = Arrays.copyOf(elementData, newCapacity);
}
解析:方法grow()接收到引數10,進過計算,執行newCapacity = minCapacity;這行程式,此時變數newCapacity的值為10,然後進行陣列複製操作,複製新陣列的長度為10,為此ArrayList集合初始化建立過程完畢。
建立ArrayList物件分析:帶有初始化容量構造方法
ArrayList有引數構造方法分析:new ArrayList(10)
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
解析:建立ArrayList集合,傳遞引數10,變數initialCapacity接收到10,直接進行陣列的建立:this.elementData = new Object[initialCapacity]
。如果傳遞的引數為0,那麼結果就和使用無引數構造方法相同,如果傳遞的引數小於0,丟擲IllegalArgumentException無效引數異常。
add新增元素方法分析:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
解析:集合新增元素,呼叫方法add並傳遞被新增的元素,首先呼叫方法ensureCapacityInternal()進行容量的檢查,然後將元素新增到elemenetData陣列中,size變數是記錄儲存多少個元素的,預設值為0,新增第一個元素的時候,size為0,新增第一個元素,再++。返回true,List集合允許重複元素。
ensureCapacityInternal()方法最終會執行到grow方法。
private void grow(int minCapacity) {
//定義變數(老容量),儲存陣列的長度 = 10
int oldCapacity = elementData.length;
//定義變數(新容量) = 老容量+老容量右移1位
//右移是二進位制位計算,相等於除以2,得出新容量=老容量+老容量/2
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
解析:例如當前的集合中的陣列長度為10,進行擴容。得出新容量+老容量=老容量/2
第七章:LinkedList集合
7.1-概述(瞭解)
java.util.LinkedList
集合資料儲存的結構是連結串列結構。方便元素新增、刪除的集合。
集合特點:元素增刪快,查詢慢,執行緒不安全,執行速度快。
LinkedList是一個雙向連結串列,那麼雙向連結串列是什麼樣子的呢,我們用個圖瞭解下:
7.2-特有方法(瞭解)
實際開發中對一個集合元素的新增與刪除經常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。這些方法我們作為瞭解即可:
public void addFirst(E e)
:將指定元素插入此列表的開頭。public void addLast(E e)
:將指定元素新增到此列表的結尾。public E getFirst()
:返回此列表的第一個元素。public E getLast()
:返回此列表的最後一個元素。public E removeFirst()
:移除並返回此列表的第一個元素。public E removeLast()
:移除並返回此列表的最後一個元素。public E pop()
:從此列表所表示的堆疊處彈出一個元素。public void push(E e)
:將元素推入此列表所表示的堆疊。public boolean isEmpty()
:如果列表不包含元素,則返回true。
LinkedList是List的子類,List中的方法LinkedList都是可以使用,這裡就不做詳細介紹,我們只需要瞭解LinkedList的特有方法即可。在開發時,LinkedList集合也可以作為堆疊,佇列的結構使用。
LinkedList list = new LinkedList();
list.add("a");
list.add("b");
// public void addFirst(E e) :將指定元素插入此列表的開頭。
list.addFirst("A");
// public void addLast(E e) :將指定元素新增到此列表的結尾。
list.addLast("B");
System.out.println(list); // [A, a, b, B]
// public E getFirst() :返回此列表的第一個元素。
System.out.println(list.getFirst()); // A
// public E getLast() :返回此列表的最後一個元素。
System.out.println(list.getLast()); // B
// public E removeFirst() :移除並返回此列表的第一個元素。
list.removeFirst();
// public E removeLast() :移除並返回此列表的最後一個元素。
list.removeLast();
System.out.println(list); //[a, b]
// public E pop() :從此列表所表示的堆疊處彈出一個元素。
list.pop();
System.out.println(list); // [b]
// public void push(E e) :將元素推入此列表所表示的堆疊。
list.push("a");
System.out.println(list); // [a, b]
// public boolean isEmpty() :如果列表不包含元素,則返回true。
System.out.println(list.isEmpty()); // false
7.3-原始碼分析(瞭解)
LinkedList成員變數分析:
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
}
解析:成員變數size是長度,記錄了集合中儲存元素的個數。first和last分別表示連結串列開頭和結尾的元素,因此連結串列可以方便的操作開頭元素和結尾元素。
LinkedList內部類Node類分析:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
解析:LinkedList集合中的內部類Node,表示連結串列中的節點物件,Node類具有3個成員變數:
- item:儲存的物件。
- next:下一個節點。
- prev:上一個節點。
從Node類的原始碼中可以分析出,LinkedList是雙向連結串列,一個物件,他記錄了上一個節點,也記錄了下一個節點。
LinkedList新增元素方法add()分析:
public boolean add(E e) {
linkLast(e);
return true;
}
linkLast方法
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
解析:呼叫集合方法add()新增元素,本質上呼叫的是linkLast()方法進行新增。
final Node<E> l = last
:當集合中新增第一個元素時last=null。final Node<E> newNode = new Node<>(l, e, null)
:建立Node類內部類物件,傳遞null(上一個節點),被新增的元素和null(下一個節點)。last = newNode
:將新增的節點newNode,複製給連結串列中的最後一個節點last。if(l == null)
:第一次新增元素時,結果為true,first=newNode,連結串列中的第一個節點=新新增的節點。size++
:記錄了集合中元素的個數。modCount++
:記錄了集合被操作的次數。
LinkedList獲取元素方法get()分析
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
node方法
Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
解析:index < (size >> 1)採用二分法,如果要獲取元素的索引小於長度的一半,那麼就從0開始,找到集合長度的一半,如果要獲取的元素的長度大於集合的一半,那麼就從最大索引開始,找到集合長度的一半。
結論:連結串列本身並沒有索引,當我們通過索引獲取的時候,內部採用了迴圈到集合長度的方式依次查詢的。
第八章:綜合案例
8.1-需求
按照鬥地主的規則,完成洗牌發牌的動作。
具體規則:
- 使用54張牌打亂順序,
- 三個玩家參與遊戲,
- 三人交替摸牌,每人17張牌,
- 最後三張留作底牌。
8.2-分析
牌可以設計為一個ArrayList<String>
,每個字串為一張牌。
每張牌由花色數字兩部分組成,我們可以使用花色集合與數字集合巢狀迭代完成每張牌的組裝。
牌由Collections類的shuffle方法進行隨機排序。
8.3-程式碼
package www.penglei666.com;
import java.util.ArrayList;
import java.util.Collections;
public class Poker {
public static void main(String[] args) {
/*
* 1: 準備牌操作
*/
//1.1 建立牌盒 將來儲存牌面的
ArrayList<String> pokerBox = new ArrayList<String>();
//1.2 建立花色集合
ArrayList<String> colors = new ArrayList<String>();
//1.3 建立數字集合
ArrayList<String> numbers = new ArrayList<String>();
//1.4 分別給花色 以及 數字集合新增元素
colors.add("♥");
colors.add("♦");
colors.add("♠");
colors.add("♣");
for(int i = 2;i<=10;i++){
numbers.add(i+"");
}
numbers.add("J");
numbers.add("Q");
numbers.add("K");
numbers.add("A");
//1.5 創造牌 拼接牌操作
// 拿出每一個花色 然後跟每一個數字 進行結合 儲存到牌盒中
for (int i =0 ; i<colors.size() ;i++) {
//color每一個花色 guilian
//遍歷數字集合
for(int j = 0; j <numbers.size() ; j++){
//結合
String card = colors.get(i)+numbers.get(j);
//儲存到牌盒中
pokerBox.add(card);
}
}
//1.6大王小王
pokerBox.add("小☺");
pokerBox.add("大☠");
// System.out.println(pokerBox);
//洗牌 是不是就是將 牌盒中 牌的索引打亂
// Collections類 工具類 都是 靜態方法
// shuffer方法
/*
* static void shuffle(List<?> list)
* 使用預設隨機源對指定列表進行置換。
*/
//2:洗牌
Collections.shuffle(pokerBox);
//3 發牌
//3.1 建立 三個 玩家集合 建立一個底牌集合
ArrayList<String> player1 = new ArrayList<String>();
ArrayList<String> player2 = new ArrayList<String>();
ArrayList<String> player3 = new ArrayList<String>();
ArrayList<String> dipai = new ArrayList<String>();
//遍歷 牌盒 必須知道索引
for(int i = 0;i<pokerBox.size();i++){
//獲取 牌面
String card = pokerBox.get(i);
//留出三張底牌 存到 底牌集合中
if(i>=51){//存到底牌集合中
dipai.add(card);
} else {
//玩家1 %3 ==0
if(i%3==0){
player1.add(card);
}else if(i%3==1){//玩家2
player2.add(card);
}else{//玩家3
player3.add(card);
}
}
}
//看看
System.out.println("東方月初:"+player1);
System.out.println("塗山紅紅:"+player2);
System.out.println("王權富貴:"+player3);
System.out.println("底牌:"+dipai);
}
}