Java的泛型和通配符


泛型:
1.泛型類
    class A<T>{
    }
2.在創建實例時,需要為其類型變量賦值

3.泛型方法
    class A<T>{
        public T fun1(){}
        public void fun2(T t){}
        //以上兩個都不是泛型方法,他們是泛型類里面的一個方法
        //發現方法要求需要在方法上有泛型的定義
        public <T> T fun3(){}//此為泛型方法
    }

    class B{
        public <T> fun1(){}//也為泛型方法,泛型方法不一定要在泛型類中
    }
*泛型方法和泛型類並沒有直接的關系,

4.泛型類的使用
    *泛型類中定義的泛型
        >可以在方法的返回值中使用
        >可以在方法的參數中使用
        >可以在局部變量是使用
    class C<T>{
        public T fun1(){
            T t = ...//可以的
            new T()//不可以的,會報錯
        }
        public void fun2(T t){}
    }
簡單來記:泛型可以在左邊使用而不可以在右邊使用。

5.泛型的繼承和實現
    *子類不是泛型類:需要給父類傳遞一個具體的類型常量
        >此時父類中所有的泛型參數都會被此類型常量給替換掉
    *子類是泛型類:可以給父類傳遞一個具體的類型參數,也傳遞一個泛型參數
    class AA1 extends A<String>{}
    class AA2<E> extends A<E>{}


=========================================
=========================================
=========================================

泛型的通配符

1. 通配符使用的場景

  方法的形參!

2. 通配符的優點
  使方法更加通用!

3. 通配符分類
  無界通配:?
  子類限定:? extends Object
  父類限定:? super Integer

4. 通配符缺點
  使變量使用上不再方便
  無界:參數和返回值為泛型的方法,不能使用!
  子類:參數為泛型的方法不能使用
  父類:返回值為泛型的方法不能使用

5. 比較通配符
boolean addAll(Collection<E> c)

List<Number> numList = new ArrayList<Number>();
List<Integer> intList = new ArrayList<Integer>();
numList.addAll(intList);//addAll(Collection<Number> c), 傳遞的是List<Integer>,報錯


boolean addAll(Collection<? extends E> c)

List<Number> numList = new ArrayList<Number>();
List<Integer> intList = new ArrayList<Integer>();
numList.addAll(intList);//addAll(Collection<? extends Number> c), 傳遞的是List<Integer>,通過

 

代碼演示

 1 package genericity;
 2 
 3 public class Demo1 {
 4 
 5    class A<T>{
 6        private T t;
 7        public T fun1(){
 8            return t;
 9        }
10        
11        public void fun2(T t){
12            
13        }
14        
15    }//是泛型類
16    
17    class B extends A<String>{}//B就不是泛型類
18    
19    class C<E> extends A<Integer>{}//也是泛型類
20    
21    class D<E> extends A<E>{}//也是泛型類
22    
23    public void fun1(){
24        D<String> d = new D<String>();//此時class D 和 class E 中的泛型都被String給替換了
25    }
26 }

 

 

  1 package genericity;
  2 
  3 import java.util.ArrayList;
  4 import java.util.List;
  5 
  6 import org.junit.Test;
  7 
  8 public class Demo2 {
  9 
 10     @Test
 11     public void fun1(){//集合和數組的較量
 12         /*
 13          * 第一次較量
 14          * 數組:我可以創建一個什么都可以存在的10空間
 15          * 集合:我可以創建一個什么都放而且無限的空間
 16          */
 17         Object[] arr1 = new Object[10];
 18         List list1 = new ArrayList();
 19         
 20         /*
 21          * 第二次較量
 22          * 數組:我可以創建一個只存放String類型的10空間
 23          * 集合:在以前我不行,不過現在我也可以,我可以創建一個只存放String類型的無限空間。
 24          */
 25         String[] arr2 = new String[10];
 26         List<String> list2 = new ArrayList<String>();
 27         
 28         /*
 29          * 第三次較量
 30          * 數組:我可以使用Object[]來存在String[],但是arr3[0] = new Integer(100);//編程不報錯,運行報:ArrayStoreException
 31          * 集合:因為泛型的擦除,直接不給我編譯通過 List<Object> list3 = new ArrayList<String>()
 32          */
 33         Object[] arr3 = new String[10];
 34         arr3[0] = new Integer(100);//編程不報錯,運行報:ArrayStoreException
 35         
 36 //        List<Object> list3 = new ArrayList<String>();
 37           /**
 38            * 上面的代碼報錯,因為泛型只有編譯器認識,而JVM對泛型根本不識別,泛型會在
 39            * 運行時擦除,如果上面代碼不報錯,而且運行時泛型又會擦除,那么就好出現下面的笑話
 40            * list.add(new Integer(100)),那么數組就好笑話集合,你什么東西都能放,
 41            * 還有什么限制,笑話。
 42            * 
 43            * 然后我們把這個問題放大,對一個打印集合里面數據的方法,
 44            */
 45     }
 46     
 47     public void fun2(){
 48         List<Integer> intList = new ArrayList<Integer>();
 49         
 50         List<String> strList = new ArrayList<String>();
 51 //        print1(intList);//直接報錯,原因和上面的一樣,因為有一個實參向形參賦值的過程,編譯器直接不讓通過 List<Object> list= intList=new ArrayList<Integer>();
 52         //思考:那每個不同類型的集合都需要不同的打印方法,那方法是也太多了,所以就有了通配符的出現
 53         
 54         //這樣就可以使用通用的打印方法了
 55         print2(intList);
 56         print2(strList);
 57     }
 58     
 59     public void print1(List<Object> list){
 60         
 61     }
 62     
 63     /**
 64      * 這里的?就是通配符
 65      * @param list
 66      */
 67     public void print2(List<?> list){
 68         /*
 69          * 思考:雖然都可以調用了,但是卻帶來了一些參數使用上面的限制
 70          */
 71 //        list.add(new Integer(100));//報錯,因為並不知道傳遞進來的到底是上面,如果是String,那編程通過就笑話了,add()作廢
 72         Object obj = list.get(0);//其實這個參數可以使用的原因是因為Object為所有類的父類,不讓這個get()方法也作廢
 73         
 74         /*
 75          * 小結:
 76          *      1、當使用通配符時,對泛型類中的參數為泛型的方法起到了副作用,不能再使用!
 77          *      2、當使用通配符時,泛型類中返回值為泛型的方法,也作廢了!
 78          * 通配符的好處:可以使泛型類型更加通用!尤其是在方法調用時形參使用通配符!
 79          */
 80     }
 81     
 82     public void fun3(){
 83         List<Integer> intList = new ArrayList<Integer>();
 84         List<Long> longList = new ArrayList<Long>();
 85         print3(intList);
 86         print3(longList);
 87     }
 88     
 89     /**
 90      * 子類統配,必須是Number及Number的子類才可以傳參
 91      * 這樣的缺點是:降低了參數的靈活性,但是關閉一扇大門就會打開一扇大門
 92      * 因為所有累都是Number的子類,所有返回值可以使用Number來接受,get()方法獲得解放,即返回值為泛型的方法可以使用了
 93      * @param list
 94      */
 95     public void print3(List<? extends Number> list){
 96         Number nu = list.get(0);//正確
 97 //        list.add(new Integer(100));//但add()方法還是被廢,以為不知道具體傳入的哪一個子類,如果傳入的是Long,加入Integer就笑話了
 98     }
 99     
100     /**
101      * 父類統配,只允許Integer傳遞參數
102      * 這樣的缺點是:降低了參數的靈活性,但是關閉一扇大門就會打開一扇大門
103      * 好處是因為所有類都是Integer的父類,參數為泛型的所有方法都可以使用了
104      * 但是相反的,返回值為泛型類型的方法就不能使用,因為子類不能接收父類的值
105      * @param list
106      */
107     public void print4(List<? super Integer> list){
108         list.add(new Integer(100));//正確
109         /*
110          * 但返回值為泛型的方法就不能使用了
111          */
112 //        Integer nu = list.get(0);//報錯
113     }
114     
115     
116 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM