目錄
- 泛型的概念
- 使用泛型的好處
- 泛型的使用
- 泛型的定義
- 自定義泛型結構
- 自定義泛型類、泛型介面
- 自定義泛型方法
- 泛型在繼承上的體現
- 泛型中通配符的使用
泛型的概念
所謂泛型,就是允許在定義類、介面時通過一個標識表示類中某個屬性的型別或者是某個方法的回傳值及引數型別,這個型別引數將在使用時(例如,繼承或實作這個介面,用這個型別宣告變數、創建物件時)確定(即傳入實際的型別引數,也稱為型別實參),
使用泛型的好處
- 解決元素存盤的安全性問題,好比商品、藥品標簽,不會弄錯,
- 解決獲取資料元素時,需要型別強制轉換的問題,好比不用每回拿商品、藥品都要辨別,
- Java泛型可以保證如果程式在編譯時沒有發出警告,運行時就不會產生ClassCastException例外,同時,代碼更加簡潔、健壯,
泛型的使用
泛型的定義
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) {
//
//}
//}
}
自定義泛型結構
自定義泛型類、泛型介面
- 泛型類可能有多個引數,此時應將多個引數一起放在尖括號內,比如:
<E1,E2,E3> - 泛型類的構造器如下:public GenericClass(){},
而下面是錯誤的:public GenericClass(){} - 實體化后,操作原來泛型位置的結構必須與指定的泛型型別一致,
- 泛型不同的參考不能相互賦值,
盡管在編譯時ArrayList和ArrayList是兩種型別,但是,在運行時只有一個ArrayList被加載到JVM中, - 泛型如果不指定,將被擦除,泛型對應的型別均按照Object處理,但不等價于Object,
- 經驗:泛型要使用一路都用,要不用,一路都不要用,
- 如果泛型結構是一個介面或抽象類,則不可創建泛型類的物件,
- jdk1.7,泛型的簡化操作:ArrayList flist = new ArrayList<>();
- 泛型的指定中不能使用基本資料型別,可以使用包裝類替換,
- 在類/介面上宣告的泛型,在本類或本介面中即代表某種型別,可以作為非靜態屬性的型別、非靜態方法的引數型別、非靜態方法的回傳值型別,但在靜態方法中不能使用類的泛型,
- 例外類是不能用泛型的
- 不能使用new E[],但是可以:E[] elements = (E[])new Object[capacity];
參考:ArrayList原始碼中宣告:Object[] elementData,而非泛型引數型別陣列. - 父類有泛型,子類可以選擇保留泛型也可以選擇指定泛型型別:
● 子類不保留父類的泛型:按需實作
→ 沒有型別 擦除
→ 具體型別
● 子類保留父類的泛型:泛型子類
→ 全部保留
→ 部分保留
結論:子類必須是“富二代”,子類除了指定或保留父類的泛型,還可以增加自己的泛型
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> {
}
自定義泛型方法
方法,也可以被泛型化,不管此時定義在其中的類是不是泛型類,在泛型方法中可以定義泛型引數,此時,引數的型別就是傳入資料的型別,
泛型方法的格式:[訪問權限] <泛型> 回傳型別 方法名([泛型標識 引數名稱]) 拋出的例外
public class DAO {
public <E> E get(int id, E e) {
E result = null;
return result;
}
}
泛型在繼承上的體現
如果B是A的一個子型別(子類或者子介面),而G是具有泛型宣告的類或介面,G< B >并不是G< A >的子型別!
比如:String是Object的子類,但是List< String >并不是List< Object >的子類,
public void testGenericAndSubClass() {
Person[] persons = null;
Man[] mans = null;
// 而 Person[] 是 Man[] 的父類.
persons = mans;
Person p = mans[0];
// 在泛型的集合上
List<Person> personList = null;
List<Man> manList = null;
// personList = manList;(報錯) }
泛型中通配符的使用
1.使用型別通配符:?
比如:List<?> ,Map<?,?>
List<?>是List、List等各種泛型List的父類,
2.讀取List<?>的物件list中的元素時,永遠是安全的,因為不管list的真實型別是什么,它包含的都是Object,
3.寫入list中的元素時,不行,因為我們不知道c的元素型別,我們不能向其中添加物件,
■ 唯一的例外是null,它是所有型別的成員
● <?>
允許所有泛型的參考呼叫
● 通配符指定上限
上限extends:使用時指定的型別必須是繼承某個類,或者實作某個介面,即<=
● 通配符指定下限
下限super:使用時指定的型別不能小于操作的類,即>=
● 舉例:
→ <? extends Number> (無窮小 , Number]
只允許泛型為Number及Number子類的參考呼叫
→ <? super Number> [Number , 無窮大)
只允許泛型為Number及Number父類的參考呼叫
→ <? extends Comparable>
只允許泛型為實作Comparable介面的實作類的參考呼叫
public static void printCollection3(Collection<? extends Person> coll) {
//Iterator只能用Iterator<?>或Iterator<? extends Person>.why?
Iterator<?> iterator = coll.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
} }
public static void printCollection4(Collection<? super Person> coll) {
//Iterator只能用Iterator<?>或Iterator<? super Person>.why?
Iterator<?> iterator = coll.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
} }
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/181347.html
標籤:其他
上一篇:Java - 【集合框架一:概述】List、Map、Set
下一篇:JVM基礎:類的加載
