背景java
咱們都知道泛型本質上是提供類型的"類型參數",它們也被稱爲參數化類型(parameterized type)或參量多態(parametric polymorphism)。其實泛型思想並非 Java 最早引入的,C++ 中的模板就是一個運用泛型的例子。安全
GJ(Generic Java)是對 Java 語言的一種擴展,是一種帶有參數化類型的 Java 語言。用 GJ 編寫的程序看起來和普通的 Java 程序基本相同,只不過多了一些參數化的類型同時少了一些類型轉換。實際上,這些 GJ 程序也是首先被轉化成通常的不帶泛型的 Java 程序後再進行處理的,編譯器自動完成了從 Generic Java 到普通 Java 的翻譯。ui
什麼是真實的java泛型spa
咱們都知道編譯器會進行泛型擦除,編譯器能夠在對源程序(帶有泛型的 Java 代碼)進行編譯時使用泛型類型信息保證類型安全,對大量若是沒有泛型就不會去驗證的類型安全約束進行驗證,同時在生成的字節碼當中,將這些類型信息清除掉。.net
按照理解,泛型擦除後將不能找回原來的類型,都是Object形式的,真的如此嗎?下面咱們先驗證一下:
public static void main(String[] args) { ArrayList<Integer> ints = new ArrayList<Integer>(); ints.add(1); ints.add(2); ints.add(3); ArrayList<String> sts = new ArrayList<String>(); sts.add("a"); sts.add("b"); sts.add("c"); System.out.println(ints.getClass() == sts.getClass()); }
上面打印的結果是true,緣由是:
編譯器能夠在對源程序(帶有泛型的 Java 代碼)進行編譯時使用泛型類型信息保證類型安全,對大量若是沒有泛型就不會去驗證的類型安全約束進行驗證,同時在生成的字節碼當中,將這些類型信息清除掉。翻譯
按照理解,泛型擦除後將不能找回原來的類型,都是Object形式的,真的如此嗎?code
看一下以下代碼:blog
import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; public class ClassTest { public static void main(String[] args) throws Exception { ParameterizedType type = (ParameterizedType) Bar.class.getGenericSuperclass(); System.out.println(type.getActualTypeArguments()[0]); ParameterizedType fieldType = (ParameterizedType) Foo.class.getField("children").getGenericType(); System.out.println(fieldType.getActualTypeArguments()[0]); ParameterizedType paramType = (ParameterizedType) Foo.class.getMethod("foo", List.class) .getGenericParameterTypes()[0]; System.out.println(paramType.getActualTypeArguments()[0]); System.out.println(Foo.class.getTypeParameters()[0] .getBounds()[0]); } class Foo<E extends CharSequence> { public List<Bar> children = new ArrayList<Bar>(); public List<StringBuilder> foo(List<String> foo) {return null; } public void bar(List<? extends String> param) {} } class Bar extends Foo<String> {} }
打印出get
class java.lang.String class com.javapuzzle.davidwang456.ClassTest$Bar class java.lang.String interface java.lang.CharSequence
你會發現每個類型參數都被保留了,並且在運行期能夠經過反射機制獲取到。那麼到底什麼是「類型擦除」?至少某些東西被擦除了吧?是的。事實上,除告終構化信息外的全部東西都被擦除了 —— 這裏結構化信息是指與類結構相關的信息,而不是與程序執行流程有關的。換言之,與類及其字段和方法的類型參數相關的元數據都會被保留下來,能夠經過反射獲取到。編譯器
參考資料
【1】http://techblog.bozho.net/on-java-generics-and-erasure/
【2】https://www.ibm.com/developerworks/cn/java/j-lo-gj/?mhsrc=ibmsearch_a&mhq=%E7%B1%BB%E5%9E%8B%E6%93%A6%E9%99%A4