Java泛型在集合使用與自定義及繼承上的體現和通配符的使用

泛型的概念

集合容器類在設計階段/聲明階段不能確定這個容器實際存的是什麼類型的對象,所以在JDK1.5之前隻能把元素類型設計為Object,JDK1.5之後使用泛型來解決。因為這個時候除瞭元素的類型不確定,其他的部分是確定的,例如關於這個元素如何保存,如何管理等是確定的,因此把元素的類型設計成一個參數,這個類型參數叫做泛型。Collection<E>ArrayList<E><E>就是類型參數,即泛型。

所謂泛型,就是允許在定義類、接口時通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數類型。這個類型參數將在使用時(例如,繼承或實現這個接口,用這個類型聲明變量、創建對象時)確定(即傳入實際的類型參數,也稱為類型實參)。

從JDK1.5以後,Java引入瞭“參數化類型(Parameterized type)”的概念,允許在創建集合時再指定集合元素的類型,正如:List<String>,這表明該List隻能保存字符串類型的對象。JDK1.5改寫瞭集合框架中的全部接口和類,為這些接口、類增加瞭泛型支持,從而可以在聲明集合變量、創建集合對象時傳入類型實參。

在這裡插入圖片描述

在這裡插入圖片描述

集合中使用泛型

Collection中使用泛型:

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @Author: Yeman
 * @Date: 2021-09-24-15:10
 * @Description:
 */
public class GenericTest {
    public static void main(String[] args) {
    	//如下在實例化的時候在<>中填入需要的類型即可(不可以是基本數據類型)
        ArrayList<Integer> list = new ArrayList<>();
        list.add(99);
        list.add(0);
        list.add(121);

        //遍歷方式一
        for (Integer integer : list){
            System.out.println(integer);
        }
        System.out.println("=====================");
        //遍歷方式二
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

Map中使用泛型:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @Author: Yeman
 * @Date: 2021-09-24-15:10
 * @Description:
 */
public class GenericTest {
    public static void main(String[] args) {
        //如下如下在實例化的時候在<>中填入需要的類型即可(不可以是基本數據類型)
        // 註意因為Map是鍵值對,因此需要分別填入“鍵”和“值”所需要的類型
        HashMap<String, Integer> map = new HashMap<>();
        map.put("Jack",26);
        map.put("Marry",18);
        map.put("Tom",20);
        map.put("Lily",22);

        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}

自定義泛型結構

1、泛型類、泛型接口

①泛型的聲明
interface List<T>{}class GenTest<K,V>{}class student <T extends Person> {}
其中,T,K,V不代表值,而是表示類型。這裡使用任意字母都可以,常用T表示,是Type的縮寫。

②泛型的實例化

List<String> strList = new ArrayList<String>();
Iterator<Customer> iterator = customers.iterator();

<>裡面隻能是類,不能用基本數據類型填充,可以使用包裝類填充。把一個集合中的內容限制為一個特定的數據類型,這就是Generic的核心思想。

泛型類可能有多個參數,此時可將多個參數一起放在尖括號內,如:<E1,E2,E3>

泛型類的構造器與非泛型一樣:public GenericClass(){}
public GenericClass<E>(){}是錯誤的。

泛型不同的引用不能相互賦值:盡管在編譯時ArrayList<String>ArrayList<Integer>是兩種類型,但是,在運行時隻有一個ArrayList被加載到JVM中。

在類/接口上聲明的泛型,在本類或本接口中即代表某種類型,可以作為非靜態屬性的類型、非靜態方法的參數類型、非靜態方法的返回值類型。但在靜態方法中不能使用類的泛型,因為靜態成員是隨著類加載而加載的,而類型的指定是在實例化時才確定的。

異常類不能使用泛型。

不能new E[],但是可以E[] elements = (E[])new Object[capacity];

父類有泛型,子類可以選擇保留泛型也可以選擇指定泛型類型,子類除瞭指定或保留父類的泛型,還可以增加自己的泛型:

class Father<T1, T2> {
}
// 子類不保留父類的泛型
// 1)沒有類型 擦除
class Son1 extends Father {// 等價於class Son extends Father<Object,Object>{
}
// 2)指定類型
class Son2 extends Father<Integer, String> {
}
// 子類保留父類的泛型
// 1)全部保留
class Son3<T1, T2> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2> extends Father<Integer, T2> {
}
class Father<T1, T2> {
}
// 子類不保留父類的泛型
// 1)沒有類型 擦除
class Son<A, B> extends Father{//等價於class Son extends Father<Object,Object>{
}
// 2)具體類型
class Son2<A, B> extends Father<Integer, String> {
}
// 子類保留父類的泛型
// 1)全部保留
class Son3<T1, T2, A, B> extends Father<T1, T2> {
}
// 2)部分保留
class Son4<T2, A, B> extends Father<Integer, T2> {
}
class Person<T> {
    // 使用T類型定義變量
    private T info;

    // 使用T類型定義一般方法
    public T getInfo() {
        return info;
    }

    public void setInfo(T info) {
        this.info = info;
    }

    // 使用T類型定義構造器
    public Person() {
    }

    public Person(T info) {
        this.info = info;
    }
}    

2、泛型方法

方法,也可以被泛型化,不管此時定義在其中的類是不是泛型類。在泛型方法中可以定義泛型參數,此時,參數的類型就是傳入數據的類型。

訪問權限 是否為靜態 <泛型> 返回類型 方法名(泛型標識 參數名稱,...) 異常{
	//方法體
}
public class Test {
	public <E> E get(int id, E[] arry) {
		E result = null;
		return result;
	}
}

泛型在繼承上的體現

如果B是A的一個子類型(子類或者子接口),而G是具有泛型聲明的類或接口,G<B>並不是G<A>的子類型!比如:String是Object的子類,但是List<String>並不是List<Object>的子類,不能相互賦值。而反過來,如下是可以的:

ArrayList<String> arrayList = new ArrayList<>();
List<String> list = arrayList;

在這裡插入圖片描述

通配符的使用

1、使用

比如:List<?>Map<?,?>
List<?>List<String>List<Object>等各種泛型List的父類。

讀取List<?>的對象list中的元素時,永遠是安全的,因為不管list的真實類型是什麼,都包含於Object。而不能向其中添加(寫入)對象。除瞭null,因為它是所有類型的成員:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // 編譯時錯誤
public static void main(String[] args) {
	List<?> list = null;
	list = new ArrayList<String>();
	list = new ArrayList<Double>();
	list.add(3);//編譯不通過,編譯時錯誤
	list.add(null);
	List<String> l1 = new ArrayList<String>();
	List<Integer> l2 = new ArrayList<Integer>();
	l1.add("AABBCC");
	l2.add(9);
	read(l1);
	read(l2);
}
public static void read(List<?> list) {
	for (Object o : list) {
		System.out.println(o);
	}
}

在這裡插入圖片描述

2、有限制的通配符

①<?>
允許所有泛型的引用調用

②通配符指定上限
extends:使用時指定的類型必須是繼承某個類,或者實現某個接口,即<=。
<? extends Number> (無窮小 , Number],隻允許泛型為Number及Number子類的引用調用。<? extends Comparable>隻允許泛型為實現Comparable接口的實現類的引用調用。

③通配符指定下限
下限super:使用時指定的類型不能小於操作的類,即>=。
<? super Number> [Number , 無窮大),隻允許泛型為Number及Number父類的引用調用。

到此這篇關於Java泛型在集合使用與自定義及繼承上的體現和通配符的使用的文章就介紹到這瞭,更多相關Java 泛型內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: