集合引入:在學習的程序中,學習了陣列這個容器,陣列的存盤資料給我們提供了方便,但是一個簡單的陣列容器無法滿足我們的需求,所以jdk又在陣列的基礎上誕生了集合,而且在不斷的發展中,集合現在已經是一個大家族了
陣列與集合關系:
- 陣列是容器,同樣集合也是容器
- 陣列可以指定型別,同樣集合也可以指定型別
- 陣列長度是固定的不能改變,集合的長度是不定的可以改變
可以看出,集合的區別在于它可以改變自身的長度,可以改變自己的長度,所以jdk根據集合制定了很多的類,很多的方法提供我們使用,這里學習了些許常用的,
常見的三大集合介面:List介面,set介面,Map介面, 由于介面無法直接創建物件使用,所以我們絕大多數都會去使用它們的實作類,
集合簡介:
集合按照其存盤結構可以分為兩大類,分別是單列集合 java.util.Collection 和雙列集合 java.util.Map ,Collection:單列集合類的根介面,用于存盤一系列符合某種規則的元素,它有兩個重要的子介面,分別是java.util.List 和 java.util.Set ,其中, List 的特點是元素有序、元素可重復, Set 的特點是元素無序,而且不可重復, List 介面的主要實作類有java.util.ArrayList 和 java.util.LinkedList , Set 介面的主要實作類有 java.util.HashSet 和 java.util.TreeSet ,Map集合屬于雙列集合,主要實作類:HashMap<K,V>:存盤資料采用的哈希表結構,元素的存取順序不能保證一致,由于要保證鍵的唯一、不重復,需要重寫鍵的hashCode()方法、equals()方法, LinkedHashMap<K,V>:HashMap下有個子類LinkedHashMap,存盤資料采用的哈希表結構+鏈表結構,通過鏈表結構可以保證元素的存取順序一致;通過哈希表結構可以保證的鍵的唯一、不重復,需要重寫鍵的hashCode()方法、equals()方法, 圖解:
List介面:(單列有序集合)
這里的無序和有序指的是添加順序并非像(1~10)這樣的自然順序
list介面所有已知實作類如下:經常使用的是ArrayList和LinkedList,所以關于list介面我也只學習了這兩個,

ArrayList實作類
ArrayList的定義(如圖所示:ArrayList有三個構造方法):

public static void main(String[] args) { /* 第一種: 構造一個初始量為默認的集合 */ ArrayList<String> arrayList = new ArrayList<String>(); /* 第一種: 構造一個添加指定集合的ArrayList集合 */ ArrayList<String> arrayList2 = new ArrayList<String>(arrayList) ; /* 第三種: 構造一個初始量為20的集合 */ ArrayList<String> arrayList3 = new ArrayList<String>(20); }
ArrayList使用方法:
- 導包:import java.util.ArrayList;
- 創建物件:ArrayList<String> arrayList = new ArrayList<String>();
在尖括號里面的有一個 E 取自Element(元素)的首字母,代表任意元素的意思,List集合不能存盤基本資料型別 例如:int 但可以存盤它的包裝類 Integer,
ArrayList常用方法:
- add():為集合添加元素,在集合末尾追加;add(index,E element):在指定索引出添加元素,
- clear():清除集合所有元素,
contains(Object o):判斷集合是否包含該元素,包含回傳true,不包含回傳false;isEmpty():判斷元素是否不包含,與contains相反forEach(Consumer<? super E> action):對集合遍歷操作,indexOf(Object o):回傳元素索引,iterator():迭代器遍歷,remove():洗掉指定索引位置的元素;remove(Object o):洗掉指定元素,如果該元素有多個,則洗掉第一次出現的那個,set(int index, E element):修改指定索引處的元素,size():回傳集合串列長度,
代碼演示:
public class ArrayListTest { public static void main(String[] args) { ArrayList<Integer> arryList = new ArrayList<Integer>(); // 創建一個默認容量為10的集合,型別為Integer // 添加方法使用 arryList.add(12); arryList.add(-2); // 直接追加式; arryList.add(0, 67); // 索引插入式 // 遍歷集合方法 arryList.forEach((s) -> System.out.print(s + " ")); // forEach遍歷加lamdba運算式 // 是否包含方法 System.out.println(arryList.contains(21)); // 集合是否包含21,回傳false // set修改方法 arryList.set(0, 7); // 修改索引為0的元素:把67修改為7 // iterator 迭代器遍歷 Iterator<Integer> it = arryList.iterator(); System.out.print("迭代器遍歷:"); while(it.hasNext()) { System.out.print(it.next()+" "); } //回傳元素12的下標索引 System.out.println("\n12的索引:"+arryList.indexOf(12)); //remove元素洗掉方法 arryList.remove(0); //根據下標洗掉 回傳布爾型別 arryList.remove("7"); //根據內容洗掉元素,洗掉元素為7的元素,回傳布爾型 //clear()清除所有元素方法 arryList.clear(); //isEmpty 判空方法 boolean empty = arryList.isEmpty(); if (empty) { System.out.println("該集合為空"); } } }
ArrayList存盤型別:
ArrayList物件不能存盤基本型別,只能存盤參考型別的資料,類似 不能寫,但是存盤基本資料型別對應的 包裝型別是可以的,所以,想要存盤基本型別資料, <> 中的資料型別,必須轉換后才能撰寫,轉換寫法如下:
ArrayList物件型別操作:
public class ArrayListTest02 { public static void main(String[] args) { // 創建存盤學生類的集合 ArrayList<Student> studentList = new ArrayList<Student>(); //添加資料 studentList.add(new Student("張三", 21)); studentList.add(new Student("李四", 12)); studentList.add(new Student("王五", 34)); //列印:Student [name=張三, age=21]Student [name=李四, age=12]Student [name=王五, age=34] studentList.forEach((s) -> System.out.print(s)); //同樣一系列的增刪查改操作都可以在這里使用 } } //物體類 Student class Student { private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } public Student() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
LinkedList實作類
LinkedList和ArrayList一樣屬于單列集合,在集合中很多方法都是由父類介面提供,所以大不分的方法都是通用的如:在ArrayList的add方法同樣適用于LinkedList集合,但不同的實作類又會有幾個特有的方法,
LinkedList方法:
addFirst(E e):從集合開頭插入元素,addLast(E e):將指定元素添加到集合尾部,get(int index):根據索引回傳元素;getFirst():回傳串列第一個元素;getLast():回傳串列最后一個元素,offer(E e):將指定元素添加為集合的最后的一個元素;offerFirst(E e):在此集合頭部添加指定元素;offerLast(E e):在集合尾部添加元素,removeFirst():洗掉串列第一個元素,并回傳該元素;removeLast():洗掉串列最后一個元素,并回傳該元素,
代碼演示:
public class LinkedListTest { public static void main(String[] args) { //創建物件 LinkedList<Integer> linkedList = new LinkedList<Integer>(); linkedList.add(12); linkedList.add(21); linkedList.add(3); linkedList.add(32); System.out.println("初始化串列"); linkedList.forEach(System.out::println); System.out.println("獲取元素"); System.out.println(linkedList.get(1));//獲取索引為0處是元素 // 列印21 System.out.println(linkedList.getFirst());//獲取串列第一個元數 //列印12 System.out.println(linkedList.getLast());//獲取串列最后一個元素//列印32 //洗掉 Integer removeFirst = linkedList.removeFirst(); //洗掉串列第一個元數,并回傳該元素 Integer removeLast = linkedList.removeLast(); //洗掉串列最后一個元素,并回傳該元素 System.out.println("洗掉后還剩余"); linkedList.forEach(System.out::println); } }
LinkedList和ArrayList的區別:
- 結構不同:LinkedList基于鏈表的資料結構,ArrayList是基于陣列的的資料結構
有于底層的結構不同,就導致了ArrayList 元素 增刪慢,查找快 的特點 ,LinkedList 元素 增刪快,查找慢 的特點,所以根據自己的需求,在和里的場景使用兩者,兩者處理資料量不大時,其實沒啥區別,
set介面(單列無序集合)
set和list的區別:最主要的區別就是有序和無序,兩個集合在添加資料時,list集合按照添加順序依次添加,而set集合則會打亂添加順序,演示如下:
public class HashSetTest { public static void main(String[] args) { ArrayList<Number> arrList = new ArrayList<Number>(); arrList.add(new Number(1)); arrList.add(new Number(2)); arrList.add(new Number(3)); arrList.add(new Number(4)); System.out.println("list集合列印:"); arrList.forEach((s) -> System.out.println(s + " ")); /* * list集合列印: Number [i=1] Number [i=2] Number [i=3] Number [i=4] */ HashSet<Number> hashSet = new HashSet<Number>(); hashSet.add(new Number(1)); hashSet.add(new Number(2)); hashSet.add(new Number(3)); hashSet.add(new Number(4)); System.out.println("set集合列印:"); hashSet.forEach((s) -> System.out.println(s + " ")); /* * set集合列印: Number [i=3] Number [i=4] Number [i=1] Number [i=2] */ } } class Number { int i; public Number(int i) { this.i = i; } @Override public String toString() { return "Number [i=" + i + "]"; } }
Set介面兩個常用實作類:HashSet實作類 ,LinkedHashSet實作類
HashSet實作類
hashSet集合底層存盤結構:
在JDK1.8之前,哈希表底層采用陣列+鏈表實作,即使用鏈表處理沖突,同一hash值的鏈表都存盤在一個鏈表里,但是當位于一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低,而JDK1.8中,哈希表存盤采用陣列+鏈表+紅黑樹實作,當鏈表長度超過閾值(8)時,將鏈表轉換為紅黑樹,這樣大大減少了查找時間,
equals和hashCode方法的作用
從上面的案例中看到,hashSet的排列是無序的,當有需求需要將它變成有序時,就需要重寫equals和hashCode兩個方法如下:
public class HashSetTest { public static void main(String[] args) { HashSet<Number> hashSet = new HashSet<Number>(); hashSet.add(new Number(1)); hashSet.add(new Number(2)); hashSet.add(new Number(3)); hashSet.add(new Number(4)); System.out.println("set集合列印:"); hashSet.forEach((s) -> System.out.println(s + " ")); /* 重寫前: * set集合列印: Number [i=3] Number [i=4] Number [i=1] Number [i=2] */ /*重寫后: * set集合列印: Number [i=1] Number [i=2] Number [i=3] Number [i=4] */ } } class Number { int i; public Number(int i) { this.i = i; } @Override public String toString() { return "Number [i=" + i + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + i; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Number other = (Number) obj; if (i != other.i) return false; return true; } }
equals判斷兩個物件內容是否相等,hashCode判斷兩個物件地址值是否相等,這也間接的是set集合不會出現重復值,除去自己定義的參考類外,jdk里面的參考資料型別,也默認重寫了這兩個方法,(這也是set集合和list集合的一大區別):
public static void main(String[] args) { ArrayList<Integer> arrayList = new ArrayList<Integer>(); arrayList.add(12); arrayList.add(2); arrayList.add(12); arrayList.forEach(System.out::println);//列印了12,2,12允許重復值出現 System.out.println("-------------------------"); HashSet<Integer> hashSet = new HashSet<Integer>(); hashSet.add(12); hashSet.add(2); hashSet.add(12); hashSet.forEach(System.out::println);//列印了2 12,默認去重 }
LinkedHashSet實作類
LinkedHashSet概述:
LinkedHashSet 有著Linked的特性,也有這set的特性,底層也有著hash的特點,可以這樣說,LinkedHashSet 是一個有序且不能重復的集合,它是鏈表和哈希表組合的一個資料存盤結構, 所以除了重寫equals外還可以選擇LinkedHashSet 來存盤一個有序且不重復的集合,
public static void main(String[] args) { LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<Integer>(); linkedHashSet.add(21); linkedHashSet.add(2); linkedHashSet.add(28); linkedHashSet.add(11); linkedHashSet.add(10); linkedHashSet.forEach(System.out::println);//依序輸出 }
至此,單列集合結束
Map(雙列集合)
map引入:現實生活中,我們常會看到這樣的一種集合:IP地址與主機名,身份證號與個人,系統用戶名與系統用戶物件等,這種一一對應的關系,就叫做映射,Java提供了專門的集合類用來存放這種物件關系的物件,即 java.util.Map 介面,
既然是映射,所以map需要兩個參考型別,結構:Interface Map<K,V> map是介面,k代表 key(鍵值),v代表 value(值),
map常用實作類:
- HashMap<K,V>:存盤資料采用的哈希表結構,元素的存取順序不能保證一致,由于要保證鍵的唯一、不重復,需要重寫鍵的hashCode()方法、equals()方法,
- LinkedHashMap<K,V>:HashMap下有個子類LinkedHashMap,存盤資料采用的哈希表結構+鏈表結構,通過鏈表結構可以保證元素的存取順序一致;通過哈希表結構可以保證的鍵的唯一、不重復,需要重寫鍵的hashCode()方法、equals()方法,
HashMap<K,V>實作類
hashMap常用方法:
- public V put(K key, V value) : 把指定的鍵與指定的值添加到Map集合中,
- public V remove(Object key) : 把指定的鍵 所對應的鍵值對元素 在Map集合中洗掉,回傳被洗掉元素的值,
- public V get(Object key) 根據指定的鍵,在Map集合中獲取對應的值,
- boolean containsKey(Object key) 判斷集合中是否包含指定的鍵,
- public Set<K> keySet() : 獲取Map集合中所有的鍵,存盤到Set集合中,
- public Set<Map.Entry<K,V>> entrySet() : 獲取到Map集合中所有的鍵值對物件的集合(Set集合),
- public Set<K> keySet():獲取map中的所有key值存盤到set集合并回傳,
hashMap示列代碼:
public class HashMapTest { public static void main(String[] args) { HashMap<Integer, String> hashMap = new HashMap<Integer, String>(); //定義一個key為Integr型別,values為String型別的HashMap //添加方法 hashMap.put(1, "張三"); hashMap.put(2, "李四"); hashMap.put(3, "王五"); hashMap.forEach((k,v) ->System.out.println(k+"="+v)); //keySet方法 Set<Integer> keySet = hashMap.keySet();//回傳包含集合中所有key值的集合 keySet.forEach(System.out::print); } }
集合的操作都大同小異,就不寫太多了,顯得啰嗦多余,
hashMap的特點:
- 存在 k v兩個引數值
- key值不能重復,如有兩個相同,后者會覆寫前者的值
- HashMap由陣列+鏈表組成的
- 存盤的值不是有序的
- 在使用自定義的物件當引數時,需要重寫equals和hashCode方法
LinkedHashMap
看區別,LinkedHashMap和HashMap無非就是有序和無序的區別
public class LinkedHashMapTest { public static void main(String[] args) { HashMap<Integer, String> hashMap = new HashMap<Integer, String>(); hashMap.put(52, "張三"); hashMap.put(9, "李四"); hashMap.put(21, "王五"); hashMap.forEach((k,v) ->{System.out.println(k+"="+v);}); /* 隨機存盤 * 52=張三 21=王五 9=李四 */ LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<Integer, String>(); linkedHashMap.put(52, "張三"); linkedHashMap.put(9, "李四"); linkedHashMap.put(21, "王五"); linkedHashMap.forEach((k,v) ->{System.out.println(k+"="+v);}); /*有序存盤 * 52=張三 9=李四 21=王五 */ } }
不做過多的介紹,一個寫通了就都玩明白了,
集合綜合案例:
- 按照斗地主的規則,完成洗牌發牌的動作,
- 組裝54張撲克牌將
- 54張牌順序打亂
- 三個玩家參與游戲,三人交替摸牌,每人17張牌,最后三張留作底牌,
- 查看三人各自手中的牌(按照牌的大小排序)、底牌
代碼如下:
public class Poker { public static void main(String[] args) { /** 1組裝54張撲克牌 */ // 1.1 創建Map集合存盤 Map<Integer, String> pokerMap = new HashMap<Integer, String>(); // 1.2 創建 花色集合 與 數字集合 List<String> colors = new ArrayList<String>(); List<String> numbers = new ArrayList<String>(); // 1.3 存盤 花色 與數字 Collections.addAll(colors, "♦", "♣", "♥", "♠"); Collections.addAll(numbers, "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"); // 設定 存盤編號變數 int count = 1; pokerMap.put(count++, "大王"); pokerMap.put(count++, "小王"); // 1.4 創建牌 存盤到map集合中 for (String number : numbers) { for (String color : colors) { String card = color + number; pokerMap.put(count++, card);/** 2 將54張牌順序打亂 */ // 取出編號 集合 } } Set<Integer> numberSet = pokerMap.keySet(); // 因為要將編號打亂順序 所以 應該先進行轉換到 list集合中 List<Integer> numberList = new ArrayList<Integer>(); numberList.addAll(numberSet); // 打亂順序 Collections.shuffle(numberList); // 3 完成三個玩家交替摸牌,每人17張牌,最后三張留作底牌 // 3.1 發牌的編號 // 創建三個玩家編號集合 和一個 底牌編號集合 List<Integer> noP1 = new ArrayList<Integer>(); List<Integer> noP2 = new ArrayList<Integer>(); List<Integer> noP3 = new ArrayList<Integer>(); List<Integer> dipaiNo = new ArrayList<Integer>(); // 3.2發牌的編號 for (int i = 0; i < numberList.size(); i++) { // 獲取該編號 Integer no = numberList.get(i); // 發牌 // 留出底牌 if (i >= 51) { dipaiNo.add(no); } else { if (i % 3 == 0) { noP1.add(no); } else if (i % 3 == 1) { noP2.add(no); } else { noP3.add(no); } } }// 4 查看三人各自手中的牌(按照牌的大小排序)、底牌 // 4.1 對手中編號進行排序 Collections.sort(noP1); Collections.sort(noP2); Collections.sort(noP3); Collections.sort(dipaiNo); // 4.2 進行牌面的轉換 // 創建三個玩家牌面集合 以及底牌牌面集合 List<String> player1 = new ArrayList<String>(); List<String> player2 = new ArrayList<String>(); List<String> player3 = new ArrayList<String>(); List<String> dipai = new ArrayList<String>(); // 4.3轉換 for (Integer i : noP1) { // 4.4 根據編號找到 牌面 pokerMap String card = pokerMap.get(i); // 添加到對應的 牌面集合中 player1.add(card); } for (Integer i : noP2) { String card = pokerMap.get(i); player2.add(card); }for (Integer i : noP3) { String card = pokerMap.get(i); player3.add(card); } for (Integer i : dipaiNo) { String card = pokerMap.get(i); dipai.add(card); } //4.5 查看 System.out.println("令狐沖:"+player1); System.out.println("石破天:"+player2); System.out.println("鳩摩智:"+player3); System.out.println("底牌:"+dipai); } }
個人學習,內容簡略,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/79291.html
標籤:Java
