您好,登錄后才能下訂單哦!
這篇文章主要介紹“為什么不要在新代碼中使用原生態類型”,在日常操作中,相信很多人在為什么不要在新代碼中使用原生態類型問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”為什么不要在新代碼中使用原生態類型”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
一些泛型的專業術語
泛型類或泛型接口:聲明中具有一個或多個類型參數(type parameter)的類或者接口,統稱為泛型。eg,jdk1.5之后,List 接口只有單個類型參數E,表示列表的元素類型,所以他的接口名稱應該是List<E>,但是人們常常把它簡稱為List。
參數化的類型(parameterized type),構成格式是:類或接口的名稱 + 尖括號(<>)將泛型形式參數的實際類型參數列表括起來。
每個泛型都定義類一個 原生態類型(raw type),即不帶任何實際類型參數的泛型名稱。eg,List<E> 對應的原生態類型是List。原生態類型就相當于從類型聲明中刪除了泛型信息。
使用泛型進行編碼,有兩個好處:
下面我們通過一個例子闡述清楚,代碼如下:
/** * @exception ClassCastException */ private static void testGenericeBeforejdk5() { Collection stamps = new ArrayList(); stamps.add(new Coin()); for (Iterator i = stamps.iterator(); i.hasNext();){ Stamp next = (Stamp)i.next(); //ClassCastException } } private static void testGenericeAfterjdk5() { Collection<Stamp> stamps = new ArrayList(); stamps.add(new Coin());//編譯器告訴我們錯誤 } // 兩個測試內部類 static class Stamp{} static class Coin{}
Exception in thread "main" java.lang.ClassCastException: effectivejava.no23.TestGeneric$Coin cannot be cast to effectivejava.no23.TestGeneric$Stamp at effectivejava.no23.TestGeneric.testGenericeBeforejdk5(TestGeneric.java:26) at effectivejava.no23.TestGeneric.main(TestGeneric.java:14)
testGenericeAfterjdk5()方法里,我們使用了泛型定義了集合的參數類型。通過這條聲明,編譯器知道 stamps 集合應該只包含Stamp 實例,并給以保證。因此在代碼開發時,我們不小心將一個coin 實例放進stamps集合時,編譯器會及時提醒我們并產生一條編譯錯誤信息,準確告知程序員哪里出現錯誤。
Error:(20, 28) java: 不兼容的類型: effectivejava.no23.TestGeneric.Coin無法轉換為effectivejava.no23.TestGeneric.Stamp
通過比較,我們還能發現,集合使用泛型,從集合中遍歷元素時不需要再進行手工轉換了。
其一、使用原生態類型,會失掉泛型在安全性和其他表述性方面的優勢。
其二、原生態類型List 和 參數化類型List<Object>有區別。
下面通過一個例子解讀兩者的區別:
private static void testSubTyping() { List<String> strings = new ArrayList<String>(); unsafeAdd(strings, new Integer(110)); String s = strings.get(0); // exception while run the method; } /** * 方法使用了原生態類型,所以可以編譯。 */ private static void unsafeAdd(List list, Object o) { list.add(0); } /** * 方法使用了List<Object>替代原生態類型,所以編譯不會通過。 */ private static void unsafeAddV2(List<Object> list, Object o) { list.add(0); }
結論:使用List 這樣的原生態類型會丟掉類型安全性,但是使用List<Object> 這樣的參數化類型則不會。
不要在新代碼中使用原生態類型,這條規則有兩個小小的例外,原因是:泛型信息可以在運行時被編譯器擦除了。
在類文字(class literal)中必須使用原生態類型,規范不允許使用參數化類型(但允許數組類型和基本類型)[JLS,15.8.2]
ClassLiteral:
TypeName {[ ]} . class
NumericType {[ ]} . class
boolean {[ ]} . class
void . class
A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void, followed by a '.' and the token class.
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.8.2
private static void testInstanceOfInvalidOnGeneric(Object o) { if (o instanceof Set){ //一旦確定o是個Set,必須轉換為通配符類型Set<?>,而不是原生態類型Set。這樣能避免后續代碼出現運行時異常。 Set<?> set = (Set<?>) o; } }
術語 | 示例 | 所在條目 |
參數化的類型 | List<String> | 23 |
實際類型參數 | String | 23 |
泛型 | List<E> | 23 |
形式類型參數 | E | 23 |
無限制通配符類型參數 | List<?> | 23 |
原生態類型參數 | List | 23 |
有限制類型參數 | List<E extends Number> | 26 |
遞歸類型限制 | List<T extends Comparable<T>> | 27 |
有限制通配符類型參數 | List<? extends Number> | 28 |
泛型方法 | static <E> List<E> asList(E[] a) | 27 |
類型令牌 | String.class | 29 |
到此,關于“為什么不要在新代碼中使用原生態類型”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。