在學習java集合的時候,泛型是個很重要的概念,它幫助我們防止了插入集合數據類型出錯。在學習java反射的過程中,我們通過集合類對象的類類型進行操作,那麼通過這種操作對集合泛型有什麼不同?
首先我們創建兩個集合對象,其中一個帶有泛型String,另一個不帶有泛型,插入集合的元素類型不受限制
ArrayList list=new ArrayList();
ArrayList<String> list1=new ArrayList<String>();
list1.add("hello");
則我們現在可以向集合list中添加任意類型對象,而在list1中只能添加String類型的對象,如果我們向list1中加入Integer類型的數據對象,則在編譯階段會出現報錯
接下來我們通過類類型和Method來調用ArrayList類中的方法
Class c1=list.getClass();
Class c2=list1.getClass();
System.out.println(c1==c2);
輸出結果爲:
true
則兩個不同泛型的集合對象類型相同,這在我們看來是不合理的,爲什麼兩個不同泛型的對象的類型會相等呢?
這是因爲,java的泛型是類型擦除的,即java的泛型在編譯階段是有效的,而在運行階段會把類型擦除,上述的兩個集合對象均變成ArrayList<>,此時比較其類型是相等的。而java的反射操作是在運行階段進行的,繞過了相應的編譯階段而轉換成了字節流,接下類我們來測試一下,java反射操作的執行階段:
Method m=c2.getMethod("add", Object.class);
m.invoke(list1, 20);
System.out.println(list1.size());
System.out.println(list1);
通過集合的類類型進行方法的調用,這時我們向list1中插入一個int類型的數據,按照泛型的要求,這個操作會在編譯階段發生錯誤,而運行結果顯示:
2
[hello, 20]
插入集合的操作成功進行,說明此時泛型已經被“擦除”,而反射操作在運行時期進行,由此我們可以得出結論:
集合泛型在編譯階段有效,而在運行階段被“擦除”