目錄
泛型的理解:
在ArrayList中使用泛型:
在Map中使用泛型:
在接口中使用泛型:
自定義泛型類/接口與自定義泛型方法
自定義類/接口:
關于泛型類的子類:
注意點:
注意點:
自定義泛型方法:
泛型在繼承上的體現以及通配符的使用:
泛型在繼承上的體現:
通配符的使用:
關于使用通配符的類的對象的操作:
有限制條件的通配符:
泛型的理解:
泛型,就是允許在定義類、接口時通過一個標識表示類中某個屬性的類型或某個方法的返回值或參數的類型。這個類型參數將在使用時(例如,繼承或實現這個接口、創建對象或調用方法時)確定(即傳入實際的類型參數,也稱為類型實參)。
集合中不使用泛型可能會:
·類型不安全,因為add( )在沒有泛型時參數是Object類型的意味著任何類型的對象都可以添加成功。
·需要頻繁地進行強轉操作。可能會出現類型轉換異常。
在集合中使用泛型:
在ArrayList中使用泛型:
List<Integer> ll = new ArrayList<Integer>();
ll.add(78);
ll.add(89);
ll.add(80);
ll.add(34);Iterator<Integer> ii = ll.iterator();
while(ii.hasNext())
{Integer i = ii.next();int score = i;System.out.println(i);
}
此處用泛型限制ll集合中只能添加Integer類型的參數。
new對象時的后面的<>里的泛型的類型可以不寫,因為會通過前面的聲明處的泛型類型自行推斷。
在Map中使用泛型:
//jdk7的特性,類型推斷,即以下的后面的尖括號不用寫泛型類型,會自行推斷。HashMap<String,Integer> map = new HashMap<>();map.put("aa",11);map.put("bb",22);map.put("cc",33);// Iterator<Map.Entry<String,Integer>> ii = map.entrySet().iterator();
// while(ii.hasNext())
// {
// Map.Entry<String,Integer> ee = ii.next();
// System.out.println(ee.getKey() + "-->" + ee.getValue());
// }//var也屬于類型推斷。var ii = map.entrySet().iterator();while(ii.hasNext()){var ee = ii.next();System.out.println(ee.getKey() + "-->" + ee.getValue());}}
此處的map的調用entrySet之后的返回值對象的類型應該是Map.Entry<String,Integer>類型,所以泛型里的類型應該是Map.Entry<String,Integer>,在新特性中,可以使用var代替聲明,進行類型推斷。
jdk5.0中,集合框架在聲明接口和實現類時,使用了泛型,在實例化集合對象時,如果沒有使用泛型,則認為操作的時Object類型的數據。如果使用了泛型,則需要指明泛型的具體類型。一旦指明了泛型的具體類型則在集合的相關方法中凡是使用泛型的位置,都替換為具體的泛型類型。
在接口中使用泛型:
例如,在聲明處實現Comparable和Comparator時,加上<>,并指明泛型類型,相應的CompareTo方法和Compare方法的參數也就與泛型的參數一致,只能限制為指定的類型。
自定義泛型類/接口與自定義泛型方法
自定義類/接口:
class A<T>{
}
interface B<T>{
}
說明(以泛型類為例):
泛型類實例化時,若不指明相關的泛型參數類型,則默認為泛型參數的類型為Object類型。實例化時,可以指明泛型參數的類型,一旦指明了泛型的類型,則在泛型類中使用泛型參數的位置,都替換為指定的類型。
關于泛型類的子類:
public class Order<T>
public class SubOrder extends Order
public class SubOrder2 extends Order<Integer>
public class SubOrder3<T> extends Order<T>
public class SubOrder4<E> extends Order<Integer>
public class SubOrder5<T,V> extends Order<T>
注意點:
①聲明完自定義泛型類以后,可以在類的內部(比如:屬性、方法、構造器中)使用類的泛型。
②創建自定義泛型類的對象時,可以指明泛型參數類型。一旦指明,內部凡是使用類的泛型參數的位置,都具體化為指定的類的泛型類型。
③如果在創建自定義泛型類的對象時,沒有指明泛型參數類型,那么泛型將被擦除,泛型對應的類型均按照Object處理,但不等價于Object。
④泛型的指定中必須使用引用數據類型。不能使用基本數據類型,此時只能使用包裝類替換。
⑤除創建泛型類對象外,子類繼承泛型類時、實現類實現泛型接口時,也可以確定泛型結構中的泛型參數。如果給泛型類提供子類時,子類也不確定泛型的類型,則可以繼續使用泛型參數。還可以在現有的父類的泛型參數的基礎上,新增泛型參數。
注意點:
①泛型類可能有多個參數,此時應將多個參數一起放在尖括號內。比如:<E1,E2,E3>
②JDK7.0開始,泛型的簡化操作:ArrayList<Fruit>?flist=?new?ArrayList<>( );
③如果泛型結構是一個接口或抽象類,則不可創建泛型類的對象。
④不能使用new?E[ ]。但是可以:E[ ]?elements?=(E[ ])new?object[capacity];
參考:ArrayList源碼中聲明:Object[ ] elementData,而非泛型參數類型數組。
⑤在類/接口上聲明的泛型,在本類或本接口中即代表某種類型,但不可以在靜態方法中使用類的泛型。
⑥異常類不能是帶泛型的。
自定義泛型方法:
格式:
權限修飾符 <E> 返回值類型 方法名(形參列表){?????????//通常在形參列表或返回值類型的位置會出現泛型參數T
}
說明:
①聲明泛型方法時一定要添加泛型參數<T>
②泛型參數在調用時指明具體的參數類型
③泛型方法可以根據需要聲明為靜態的
④泛型方法在泛型類或不是泛型類都可以。
泛型在繼承上的體現以及通配符的使用:
泛型在繼承上的體現:
G<superA>與G<A>(若superA是A的父類)并沒有子父類的關系,它們是兩個并列的無關聯類,不能體現多態性。
SuperA<E>與A<E>的關系是子父類的關系,可以體現多態性。
通配符的使用:
通配符:?
格式:A<?>? ? ?(若A是一個泛型類)
此格式代表不確定A的泛型類型的類型,此類型是A的所有確定泛型類型的類型的父類,可以與其他確定泛型類型的類型體現多態性。
關于使用通配符的類的對象的操作:
讀取數據:由于讀取的數據類型不確定,所以讀取的數據的操作都是返回Object類型。
寫入數據:由于數據類型不確定,使用通配符的類的對象不能寫入數據(特例,可以添加null),只能通過多態性接收其他對象的數據。
接受其他對象的數據:可以看作將A<E>的對象賦值給G<?>的引用。
有限制條件的通配符:
A<? extend B> :可以將A<B的子類或B類>的對象賦值給A<? extend B>的引用。
A<? super B> :可以將A<B的父類或B類>的對象賦值給A<? super B>的引用。