泛型:
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 }