泛型(Generic)

真好吃啊 發表於 2021-10-13

泛型(Generic)


1. Jdk 5.0新加的特性

2. 在集合中使用泛型:

   總結:
① 集合介面或集合類在jdk5.0時都修改為帶泛型的結構。
② 在例項化集合類時,可以指明具體的泛型型別
③ 指明完以後,在集合類或介面中凡是定義類或介面時,內部結構(比如:方法、構造器、屬性等)使用到類的泛型的位置,都指定為例項化的泛型型別。
比如:add(E e) --->例項化以後:add(Integer e)
④ 注意點:泛型的型別必須是類,不能是基本資料型別。需要用到基本資料型別的位置,拿包裝類替換
⑤ 如果例項化時,沒有指明泛型的型別。預設型別為java.lang.Object型別。
泛型(Generic)
public class GenericTest {


    //在集合中使用泛型之前的情況:
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        //需求:存放學生的成績
        list.add(78);
        list.add(76);
        list.add(89);
        list.add(88);
        //問題一:型別不安全
//        list.add("Tom");

        for(Object score : list){
            //問題二:強轉時,可能出現ClassCastException
            int stuScore = (Integer) score;

            System.out.println(stuScore);

        }

    }

    //在集合中使用泛型的情況:以ArrayList為例
    @Test
    public void test2(){
       ArrayList<Integer> list =  new ArrayList<Integer>();

        list.add(78);
        list.add(87);
        list.add(99);
        list.add(65);
        //編譯時,就會進行型別檢查,保證資料的安全
//        list.add("Tom");

        //方式一:
//        for(Integer score : list){
//            //避免了強轉操作
//            int stuScore = score;
//
//            System.out.println(stuScore);
//
//        }
        //方式二:
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            int stuScore = iterator.next();
            System.out.println(stuScore);
        }

    }

    //在集合中使用泛型的情況:以HashMap為例
    @Test
    public void test3(){
//        Map<String,Integer> map = new HashMap<String,Integer>();
        //jdk7新特性:型別推斷
        Map<String,Integer> map = new HashMap<>();

        map.put("Tom",87);
        map.put("Jerry",87);
        map.put("Jack",67);

//        map.put(123,"ABC");
        //泛型的巢狀
        Set<Map.Entry<String,Integer>> entry = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();

        while(iterator.hasNext()){
            Map.Entry<String, Integer> e = iterator.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key + "----" + value);
        }

    }


}
集合中使用泛型

 

3.如何自定義泛型結構:泛型類、泛型介面;泛型方法。
  a. 泛型類的構造器如下:public GenericClass(){}。錯誤的:public GenericClass<E>(){}
  b. 在類/介面上宣告的泛型,在本類或本介面中即代表某種型別,可以作為非靜態屬性的型別、非靜態方法的引數型別、非靜態方法的返回值型別。但在靜態方法中不能使用類的泛型
  c. 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity];參考:ArrayList原始碼中宣告:Object[] elementData,而非泛型引數型別陣列。

4. 泛型方法:[訪問許可權] <泛型> 返回型別 方法名([泛型標識 引數名稱]) 丟擲的異常
public class DAO {
public <E> E get(int id, E e) {
E result = null;
return result; } }

 

泛型(Generic)
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; }


// static的方法中不能宣告泛型
//public static void show(T t) {
//
//}
// 不能在try-catch中使用泛型定義
//public void test() {
//try {
//
//} catch (MyException<T> ex) {
//
//}
//}
}
子類保不保留父類的泛型

 

泛型(Generic)
//泛型方法:在方法中出現了泛型的結構,泛型引數與類的泛型引數沒有任何關係。
//換句話說,泛型方法所屬的類是不是泛型類都沒有關係。
//泛型方法,可以宣告為靜態的。原因:泛型引數是在呼叫方法時確定的。並非在例項化類時確定。
    public static <E>  List<E> copyFromArrayToList(E[] arr){

        ArrayList<E> list = new ArrayList<>();

        for(E e : arr){
            list.add(e);
        }
        return list;

    }
}
泛型方法是可以靜態的

 


4. 泛型在繼承方面的體現
雖然類A是類B的父類,但是G<A> 和G<B>二者不具備子父類關係,二者是並列關係。
類A是類B的父類,A<G> 是 B<G> 的父類
泛型(Generic)
    @Test
    public void test1(){

        Object obj = null;
        String str = null;
        obj = str;

        Object[] arr1 = null;
        String[] arr2 = null;
        arr1 = arr2;
        //編譯不通過
//        Date date = new Date();
//        str = date;
        List<Object> list1 = null;
        List<String> list2 = new ArrayList<String>();
        //此時的list1和list2的型別不具有子父類關係
        //編譯不通過
//        list1 = list2;
        /*
        反證法:
        假設list1 = list2;
           list1.add(123);導致混入非String的資料。出錯。

         */

        show(list1);
        show1(list2);

    }

    public void show1(List<String> list){

    }

    public void show(List<Object> list){

    }

    @Test
    public void test2(){

        AbstractList<String> list1 = null;
        List<String> list2 = null;
        ArrayList<String> list3 = null;

        list1 = list3;
        list2 = list3;

        List<String> list4 = new ArrayList<>();

    }
泛型在繼承方面的使用

 


5. 萬用字元:?
泛型(Generic)
 /*
    2. 萬用字元的使用
       萬用字元:?

       類A是類B的父類,G<A>和G<B>是沒有關係的,二者共同的父類是:G<?>


     */

    @Test
    public void test3(){
        List<Object> list1 = null;
        List<String> list2 = null;

        List<?> list = null;

        list = list1;
        list = list2;
        //編譯通過
//        print(list1);
//        print(list2);


        //
        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");
        list = list3;
        //新增(寫入):對於List<?>就不能向其內部新增資料。
        //除了新增null之外。
//        list.add("DD");
//        list.add('?');

        list.add(null);

        //獲取(讀取):允許讀取資料,讀取的資料型別為Object。
        Object o = list.get(0);
        System.out.println(o);


    }

    public void print(List<?> list){
        Iterator<?> iterator = list.iterator();
        while(iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }
    }

    /*
    3.有限制條件的萬用字元的使用。
        ? extends A:
                G<? extends A> 可以作為G<A>和G<B>的父類,其中B是A的子類
                    
        ? super A:
                G<? super A> 可以作為G<A>和G<B>的父類,其中B是A的父類
                     
     */
    @Test
    public void test4(){

        List<? extends Person> list1 = null;
        List<? super Person> list2 = null;

        List<Student> list3 = new ArrayList<Student>();
        List<Person> list4 = new ArrayList<Person>();
        List<Object> list5 = new ArrayList<Object>();

        list1 = list3;
        list1 = list4;
//        list1 = list5;

//        list2 = list3;
        list2 = list4;
        list2 = list5;

        //讀取資料:
        list1 = list3;
        Person p = list1.get(0);
        //編譯不通過
        //Student s = list1.get(0);

        list2 = list4;
        Object obj = list2.get(0);
        ////編譯不通過
//        Person obj = list2.get(0);

        //寫入資料:
        //編譯不通過
//        list1.add(new Student());

        //編譯通過
        list2.add(new Person());
        list2.add(new Student());

    }

}
萬用字元

 

 1. 萬用字元不能用在泛型方法的宣告上,返回值前面<>不能使用

public static <?> void test(ArrayList<?> list){
}

 

2. 萬用字元不能使用在泛型類的宣告上

class GenericTypeClass<?>{
}

 

3. 萬用字元不能用在建立物件上,右邊屬於建立集合物件

ArrayList<?> list2 = new ArrayList<?>();