Collection\泛型(Collection\Generics)知識總結
Collection\泛型(Collection\Generics)知識總結
1.1 集合概述
集合:集合是java中提供的一種容器,用來儲存多個數據。
集合和陣列的區別:
陣列的長度是固定的,集合的長度是可變的。
陣列中儲存的是同一型別的元素,可以儲存基本資料型別值。集合儲存的都是物件。而且物件的型別可以不一致,在開發中一般當物件多的時候,使用集合進行儲存。
1.2Collection集合
1.單列集合體繫結構
集合的框架:
(綠線是繼承關係)
List集合∶有索引、可以儲存重複元素、可以保證存取順序
ArrayList:底層是陣列實現的,查詢塊,增刪慢
LinkedList:底層是連結串列實現的,查詢慢、增刪快
Set集合∶無索引、不可以儲存重複元素、存取無序
HashSet:底層是雜湊表+(紅黑樹)實現的,無索引、不可以儲存重複元素、存取無序LinkedHashSet:底層是雜湊表+連結串列實現的,無索引、不可以儲存重複元素、可以保證存取順序
TreeSet:底層是二叉樹實現,一般用於排序
2.Collection集合常用方法
boolean add(E e); 向集合中新增元素
boolean remove(E e); 刪除集合中的某個元素
void clear(); 清空集合中所有的元素
boolean contaions(E e); 判斷集合中是否包含某個元素
boolean isEmpty(); 判斷集合是否為空
int size(); 獲取集合的長度
Object[] toArray(); 將集合轉成一個數組
程式碼:
public class Text01 { public static void main(String[] args) { Collection<String> coll = new ArrayList<>(); coll.add("Hello"); coll.add("java"); boolean result = coll.remove("Hello"); //result = true coll.clear(); System.out.println(coll); coll.add("Hello"); coll.add("java"); Object[] obj= coll.toArray(); System.out.println(obj);//[Ljava.lang.Object;@f0d1e0b for(int a = 0;a<obj.length;a++){ System.out.println(obj[a]); /*Hello java*/ } } }
1.3 Iterator迭代器
1.概念
在程式開發中,經常需要遍歷集合中的所有元素。針對這種需求,JDK專門提供了一個介面 java.util.Iterator 。
Iterator 介面也是Java集合中的一員,但它與 Collection 、 Map 介面有所不同, Collection 介面與 Map 介面主要用於儲存元素,而 Iterator 主要用於迭代訪問(即遍歷) Collection 中的元素,因此 Iterator 物件也被稱為迭代器。
想要遍歷Collection集合,那麼就要獲取該集合迭代器完成迭代操作,下面介紹一下獲取迭代器的方法:
public Iterator iterator() : 獲取集合對應的迭代器,用來遍歷集合中的元素的。
迭代:即Collection集合元素的通用獲取方式。在取元素之前先要判斷集合中有沒有元素,如果有,就把這個
元素取出來,繼續在判斷,如果還有就再取出出來。一直把集合中的所有元素全部取出。這種取出方式專業
術語稱為迭代。
Iterator介面的常用方法如下:
public E next() :返回迭代的下一個元素。
public boolean hasNext() :如果仍有元素可以迭代,則返回 true。
Iterator迭代器,是一個介面,我們無法直接使用,需要使用Iterator介面的實現類物件,獲取實現類的方式比較特殊
Collection介面中有一個方法,叫iterator(),這個方法返回的就是迭代器的實現類物件
Iterator<E> iterator() 返回在此 collection 的元素上進行迭代的迭代器。
2.迭代器的使用步驟:
1.使用集合中的方法iterator()獲取迭代器的實現類物件,使用Iterator介面接收(多型)
2.使用Iterator介面中的方法hasNaxt判斷還有沒有下一個元素
3.使用Iterator介面中的方法next取出集合中的下一個元素
程式碼:
public class Demo001 { public static void main(String[] args) { Collection<String> coll = new ArrayList(); coll.add("a"); coll.add("b"); coll.add("c"); //獲取迭代器 Iterator<String> iterator = coll.iterator(); //hasNext boolean flag = iterator.hasNext(); System.out.println(flag); //true while (iterator.hasNext()){ //next取出 String s = iterator.next(); System.out.println(s);//a b c } System.out.println("---------------------"); for(Iterator<String> it2 = coll.iterator();it2.hasNext();/*迭代器的hasNext取出元素自動向後移動一位*/){ String s = iterator.next(); System.out.println(s); } } }
3.增強for
增強for迴圈:底層使用的也是迭代器,使用for迴圈的格式,簡化了迭代器的書寫,是JDK1.5之後出現的
Collection<E>extends Iterable<E>:所有的單列集合都可以使用增強for
public interface Iterable<T>實現這個介面允許物件成為“foreach”語句的目標。
增強for迴圈:用來遍歷集合和陣列
格式:
for(集合/陣列的資料型別 變數名:集合名/陣列名){
sout(變數名);
}
程式碼:
public class Demo02_for { public static void main(String[] args) { demo01(); demo02(); } private static void demo01(){ int[] arr = {1,2,3,4,5}; for(int i:arr){ System.out.println(i); } } private static void demo02(){ ArrayList<String> coll = new ArrayList<>(); coll.add("a"); coll.add("b"); coll.add("c"); for(String s:coll){ System.out.println(s); } } }
1.4 泛型
1.概念
泛型是一種未知的資料型別,當我們不知道使用什麼資料型別的時候,可以使用泛型,泛型也可以看作是一種變數,可以用來接收資料
ArrayList集合在定義的時候,不知道集合中都會儲存什麼型別的資料,所以型別使用泛型
E e:Element 元素
T t:Type 型別
建立集合物件,不適用泛型
2.泛型的定義與使用:
程式碼:
方法類:
/* 定義一個含有泛型的類,模擬ArrayList集合 泛型是一個未知的資料型別,當我們不確定什麼什麼資料型別的時候,可以使用泛型 泛型可以接收任意的資料型別,可以使用Integer,String,Student... 建立物件的時候確定泛型的資料型別 */ public class GenericClass<E> { private E name; public E getName() { return name; } public void setName(E name) { this.name = name; } }
實現類:
public class Demo02GenericClass { public static void main(String[] args) { //不寫泛型預設為Object型別 GenericClass gc = new GenericClass(); gc.setName("只能是字串"); Object obj = gc.getName(); //建立GenericClass物件,泛型使用Integer型別 GenericClass<Integer> gc2 = new GenericClass<>(); gc2.setName(1); Integer name = gc2.getName(); System.out.println(name); //建立GenericClass物件,泛型使用String型別 GenericClass<String> gc3 = new GenericClass<>(); gc3.setName("小明"); String name1 = gc3.getName(); System.out.println(name1); } }
3.好處和弊端
好處:
集合不使用泛型,預設的型別就是Object型別,可以儲存任意型別的資料
弊端:
不安全,會引發異常
建立集合物件,使用泛型
好處:
1.避免了型別轉換的麻煩,儲存的是什麼型別,取出的就是什麼型別
2.把執行期異常(程式碼執行之後會丟擲的異常),提升到了編譯期
弊端:
泛型是什麼型別,只能儲存什麼型別的資料
程式碼:
public class GenericDemo01 { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("a"); list.add(1); Iterator it = list.iterator(); while (it.hasNext()){ Object obj = it.next(); System.out.println(obj); //想要使用String類特有的方法,length獲取字串的長度;不能使用多型,因為obj是 //Object類,不能使用其子類String特有的方法,需向下轉型 String s = (String)obj; System.out.println(s.length());//丟擲型別轉換異常 Integer cannot be cast,所以不使用泛型不安全,容易引發異常 } } }
4.泛型萬用字元:
當使用泛型或者介面時,傳遞的資料中,泛型型別不確定,可以使用萬用字元<?>表示,但是一旦使用泛型的萬用字元後,只能使用Object類中的
共性方法,集合中元素自身方法無法使用
程式碼:
/* 泛型的萬用字元: ?:代表任意的資料型別 使用方式: 不能建立物件使用 只能作為方法的引數使用 */ public class Demo05Generic { public static void main(String[] args) { ArrayList<Integer> list01 = new ArrayList<>(); list01.add(1); list01.add(2); ArrayList<String> list02 = new ArrayList<>(); list02.add("a"); list02.add("b"); printArray(list01); printArray(list02); //ArrayList<?> list03 = new ArrayList<?>(); 這是錯誤的 } /* 定義一個方法,能遍歷所有型別的ArrayList集合 這時候我們不知道ArrayList集合使用什麼資料型別,可以泛型的萬用字元<?>來接收資料型別 注意: 泛型沒有繼承概念的 */ public static void printArray(ArrayList<?> list){ //使用迭代器遍歷集合 Iterator<?> it = list.iterator(); while(it.hasNext()){ //it.next()方法,取出的元素是Object,可以接收任意的資料型別 Object o = it.next(); System.out.println(o); } } }
萬用字元的高階使用-------受限泛型(不常用)
程式碼:
/* 泛型的上限限定: ? extends E 代表使用的泛型只能是E型別的子類/本身 泛型的下限限定: ? super E 代表使用的泛型只能是E型別的父類/本身 */ public class Demo06Generic { public static void main(String[] args) { Collection<Integer> list1 = new ArrayList<Integer>(); Collection<String> list2 = new ArrayList<String>(); Collection<Number> list3 = new ArrayList<Number>(); Collection<Object> list4 = new ArrayList<Object>(); getElement1(list1); //getElement1(list2);//報錯 getElement1(list3); //getElement1(list4);//報錯 //getElement2(list1);//報錯 //getElement2(list2);//報錯 getElement2(list3); getElement2(list4); /* 類與類之間的繼承關係 Integer extends Number extends Object String extends Object */ } // 泛型的上限:此時的泛型?,必須是Number型別或者Number型別的子類 public static void getElement1(Collection<? extends Number> coll){} // 泛型的下限:此時的泛型?,必須是Number型別或者Number型別的父類 public static void getElement2(Collection<? super Number> coll){} }
本章思維導圖:
案例:
鬥地主關於準備牌/洗牌/發牌/看牌的實現:
程式碼:
package Java.Collection; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; public class DouDiZhu { public static void main(String[] args) { //1.準備牌 ArrayList<String> poker = new ArrayList(); String[] color = {"♠","♥","♣","♦"}; String[] number = {"1","2","3","4","5","6","7","8","9","10","J","Q","K"}; poker.add("大王"); poker.add("小王"); for(String colour:color){ for(String Number:number){ poker.add(colour+Number); } } //洗牌 Collections.shuffle(poker); //發牌 ArrayList<String> player01 = new ArrayList<>(); ArrayList<String> player02 = new ArrayList<>(); ArrayList<String> player03 = new ArrayList<>(); ArrayList<String> diPai = new ArrayList<>(); for(int i = 0;i<poker.size();i++){ if(i>=51){ String a = poker.get(i); diPai.add(a); }else if(i%3==0){ String a = poker.get(i); player01.add(a); }else if(i%3==1){ String a = poker.get(i); player02.add(a); }else if(i%3==2){ String a = poker.get(i); player03.add(a); } } for(int i = 0;i<diPai.size();i++){ if(i%3==0){ String a = diPai.get(i); player01.add(a); } if(i%3==1){ String a = diPai.get(i); player02.add(a); } if(i%3==2){ String a = diPai.get(i); player03.add(a); } } //看牌 System.out.println("player01:"+player01); System.out.println("player02:"+player02); System.out.println("player03:"+player03); System.out.println("底牌是:"+diPai); } } 執行結果: player01:[♠2, ♥6, ♦Q, ♥Q, ♦7, ♦8, ♣8, ♠6, 大王, 小王, ♠8, ♣3, ♣5, ♠K, ♣J, ♠J, ♦3, ♠9] player02:[♥7, ♥8, ♦1, ♥4, ♠3, ♠Q, ♦10, ♣Q, ♣10, ♥K, ♠7, ♣4, ♥1, ♥J, ♥9, ♣7, ♣6, ♦9] player03:[♣9, ♠10, ♣K, ♦2, ♦5, ♦K, ♣2, ♥5, ♦6, ♠1, ♥2, ♠5, ♦4, ♣1, ♠4, ♥3, ♥10, ♦J] 底牌是:[♠9, ♦9, ♦J]