========
-
java中的集合元素被丟進去之後就失去了類型訊息,在當取出的時候就都成爲了Object的類型
集合加入泛型可以幫助集合記憶這些訊息;
-
泛型基礎訊息:
1》修飾類的時候,寫在類的後方,區別:在調用的時候需要指明具體類型
List<String>listString = new ArrayList<String>();
2》修飾方法,寫在返回值前,區別:在調用的的時候會根據傳入的參數指明具體類型
private<T> void Test(T a){}
inta;
Stringa;
Test(a);
如上T會根據傳入的a的類型變成int|| String,不需要像類和接口那樣再調用的時候指明
3》修飾變量,可以作爲普通的修飾詞來使用
可以理解:一種特殊的修飾詞,除了類之外,可以看到《》的擺放位置都是和正常的修飾詞一致
泛型+extends:
class Apple <T>{
T info;
}
//這樣寫是錯誤的,算是使用Apple,就必須傳入實際的類型
class Orange extends Apple<T>{
}
//這樣傳入實際參數,正確
class Orange1 extends Apple<String>{
}
//不傳參數,默認Object,正確,這時會報警告:使用了未經檢查或不安全的操作
class Orange2 extends Apple{
}
-
泛型+編譯
//可以看到這裏的泛型很好的限定了List中存儲數據的類型
List<String> list = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();
//打印結果相等,不管泛型的實際類型參數是什麼,
//他們在運行的時候總有同樣的類(共一個.class文件)
System.out.println(list.getClass() == list2.getClass());
-
泛型+static
靜態的東西不能加入<>,因爲在使用的時候無法確認泛型的具體代表的實際類型,原理和3中的第一個例子相似
-
泛型+包含關係
List<String>並不能直接用List<Object>這種類型來接,他們並不是包含關係,是兩個完全不同的類型
-
泛型+通配符重要:解決了6中的問題
1》基礎:List<?>表示可以匹配任何類型
//以下開始限定範圍了
2》設置上限:List<?extends String> 表明是一個String類型或者是他的子類,上限String
3》設置下限:List<?super String> 表明是一個String類型或者是他的父類,下限String
4》使用範圍:一般在參數中使用,不可直接用於賦值,詳見下8中例子
-
不能對任何帶<?>通配符的類型進行復賦值操作(B繼承A)
List<? extends A> listb = new ArrayList<B>();
listb.add(new B());
//上面的例子是錯的,因爲listb是一個帶通配符的,so,
//它是一個不確定的類型,不能進行任何add操作
//,操作之前可以先進行強制類型轉換
//可以強制類型轉換成A或者A的子類
List<A> listA = (List<A>)listb;
listA.add(new A());
List<B> listB = (List<B>)listb;
listB.add(new B());
//注意:強制類型轉換過後就爲”確定的A&B類型“了,就不能在賦值給List<A>
List<A> listAA = (List<A>)listB;
注意:Bextends A,且
List<A>listA =(List<A>)listb;
listA.add(newB());
正確,但是List<A>= List<B>是錯誤的,這兩個類型並不具有包含關係,他們是兩個各自獨立的類型,就像本文6中所說的那樣
-
泛型+方法
private<T> void Test(T a){}
此時在方法Test中,T即被當做一個普通類型來使用
當方法有多個參數的時候,且參數之間的類型有着關係,這時候需要使用<?>通配符來表達
<T> void eat(List<? extends T> a,List<T> b){
System.out.println("eat");
}
public static void main(String[] args) {
Test test = new Test();
test.eat(new ArrayList<B>(), new ArrayList<A>());
}
-
泛型+構造器(可以理解構造器是類的一種特殊方法,與普通方法的有點區別)
public <T> Test(T t) {
}
<E> void eat(E e){
}
public static void main(String[] args) {
String t = "test";
Test test = new Test(t);
Test test1 = new <A>Test(new A());
test.eat(t);
test1.<A>eat(new A());
}
可以看到基本功能一樣,調用的時候都可以選擇指定或者不指定<T>泛型的具體類型
-
小知識:
List<>= List //調用不當(List實際存儲的類型與<>中的不匹配)的時候會導致異常
List= List<> //丟失TYPE,直接變成List的上限