List arrayList = new ArrayList(); arrayList.add("aaaa"); arrayList.add(100); arrayList.forEach(i -> { String item = (String) arrayList.get(i); Log.d("泛型", "item = " + item); }); 複製代碼
- 這樣的寫法會致使程序出現異常崩潰結束:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String 複製代碼
- 這裏的ArrayList能夠存聽任意類型,添加了一個String類型,添加了一個Integer類型,再使用時都以String的方式使用,所以程序崩潰
- 泛型就是解決這樣的問題
- 再討論另外一種狀況,若是將第一行聲明初始的代碼修改一下,那麼在編譯階段就能發現問題:
List arrayList = new ArrayList<String>(); arrayList.add("aaaa"); arrayList.add(100); // 這一步在編譯階段,編譯器就會報錯 arrayList.forEach(i -> { String item = (String) arrayList.get(i); Log.d("泛型", "item = " + item); }); 複製代碼
能夠發現,在編譯事後,程序會採起去泛型化措施.也就是說,Java中的泛型,只在編譯階段有效.在編譯過程當中,正確檢驗泛型結果後,會將泛型的相關信息擦除,而且在對象進入和離開方法的邊界處添加類型檢查和類型轉換方法java
class 類名稱 <泛型標識: 標識號,標識指定的泛型的類型> {
private 泛型標識 成員變量類型 成員變量名;
}
複製代碼
/* * 這裏的T能夠爲任意標識,一般使用T,E,K,V等形式的參數表示泛型 * 在實例化泛型時,必須指定T的具體類型 */
public class Generic<T> {
// key這個成員變量的類型爲T,T的類型由外部指定
private T key;
// 泛型構造方法形參key的類型也爲T,T的類型由外部指定
public Generic(T key) {
this.key = key;
}
// 泛型構造方法getKey的返回值類型爲T,T的類型由外部指定
public T getKey() {
}
}
複製代碼
// 定義一個泛型接口
public interface Generator<T> {
public T next();
}
複製代碼
由此能夠看到Generic< Integer >不能看做是Generic< Number >的子類.數組
public void showKeyValueWildcard(Generic<?> obj) {
Log.d("泛型測試", "key value is" + obj.getKey());
}
複製代碼
public class StaticGenerator<T> {
...
...
/* * 若是在類中定義使用泛型的靜態方法,須要添加額外的泛型聲明 - 將這個方法定義成泛型方法 * 不然會報錯: StaticGenerator cannot be refrenced from static context */
public static <T> void show(T t) {
}
}
複製代碼
/* * 這個數組建立的方式是不容許的 * List<String>[] ls = new ArrayList<String>[10]; */
// 使用通配符建立泛型數組是能夠的
List<?>[] ls = new ArrayList<?>[10];
// 下面的這個方法也是能夠的
List<String> ls = new ArrayList[10];
複製代碼
- 因爲JVM的擦除機制,在運行時JVM是不知道泛型信息的:
- 全部能夠給oa[1] 賦值一個ArrayList卻不會出現異常
- 可是在取出數據的時候要作一次類型轉換,就會出現ClassCastException
- 若是能夠進行泛型數組的聲明,那麼上面的這種狀況在編譯期將不會出現任何警告和錯誤,只有在運行時纔會報錯
- 經過對泛型數組的聲明進行限制,對於這樣的狀況,能夠在編譯期提示代碼有類型安全問題