1. 程式人生 > 其它 >Collection\泛型(Collection\Generics)知識總結

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]