Re: [J2SE] 宣告 Set<String> edge[] 出了錯誤訊息

看板java作者 ( )時間12年前 (2012/08/30 00:12), 編輯推噓1(102)
留言3則, 3人參與, 最新討論串2/2 (看更多)
※ 引述《tailsice (tailsice)》之銘言: : 請教各位前輩 : 小弟我最近寫了一支程式 : 裡面有段宣告是這樣寫的 : Set<String> edge[] = new HashSet[in + 1 : for (int i = 0; i < edge.length; i++ : edge[i] = new HashSet<String>(); : 在後面的 new HashSet[in + 1] 為什麼會出 : Type safety: The expression of type HashSet[] needs unchecked conversion : to conform to Set<String>[] : 這樣的錯誤訊息呢? : 我上網苦尋不到答案 : 所以前往跟各位前輩請教 Java 不允許 generic array,因此你只能不告訴 compiler type parameter 是什麼, 但就是因為沒有宣告,所以有 type safety 的 warning。 首先,在 runtime 時,generic 的 type parameter 是不存在的,這叫 tyep erasure, 對原因有興趣的話可以去找資料讀。 接著談一下 covariant 和 invariant 。 array 和一般的 Java 物件一樣為 covariant,可以用 supertype 來 reference subtype,但也因為如此,它需要清楚的知道物件的 type。 String[] strings = new String[2]; Object[] objects = strings; // okay 可是一個 generic 並不是 covariant。在 runtime 中,type parameter會因為 type erasure 而不存在,所以 compiler 並不會讓你用 type parameter 的 supertype 來 reference。 ArrayList<String> list = new ArrayList<String>(); ArrayList<Object> anotherList = list; // error ================================================================== 上述觀念與不允許 generic array 的關連 ? 請看下面兩個範例 Example 1 : 1 String[] strings = new String[2]; 2 Object[] objects = string; 3 objects[0] = new Integer(1); // ArrayStoreException 上面第三行會錯是因為 objects reference 的畢竟還是一個 String[], String[] 當然不可以存 Integer,在 runtime 時,這種 type 錯誤會被抓出來。 那如果 generic array 的話呢 ?假設 Java compiler 允許你這樣做 1 ArrayList<String>[] lists = new ArrayList<String>[2]; // 假設可以 2 Object[] objects = lists; 3 ArrayList<Integer> integers = new ArrayList<Integer>(); 4 integers.add(1); 5 objects[0] = integers; 6 String string = lists[0].get(0); // ClassCastException 第二行是因為 covariant 的關係,因此可以如此指定,但第五行 code 理論上應該要和第 一個例子一樣會出現錯誤,但其實並不會,因為 type parameter 在 runtime 並不存在, 因此 objects 裡面只剩 ArrayList[],所以 ArrayList<Integer> 當然可以被加到 ArrayList[] 裡面,因為 ArrayList<Integer> 滿足 ArrayList 這個 type check。 下場就是runtime時出現第六行的錯誤。為了type safe,因此打從語法上,compiler 就不準你這樣宣告。 這算是 Java 為了 generic 而導致出的一個大缺陷吧,而且不太直覺。 更詳細的解說可以讀讀這篇 www.angelikalanger.com/Articles/Papers/JavaGenerics/ArraysInJavaGenerics.htm 解法 ? Set<Set<String> 應該比較最穩的方式,也考慮到了 type safe。 雖然很醜,也不易使用,有必要的話,也可以考慮把這種資料結構用物件包起來。 -- We who cut mere stones must always be envisioning cathedrals. -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.35.186.241

08/30 10:03, , 1F
感謝大大的指點,我對泛型有了更深的認識。
08/30 10:03, 1F

08/30 15:14, , 2F
compiler 沒有不准這麼寫,只是囉唆一點,提醒要注意。
08/30 15:14, 2F

08/30 20:23, , 3F
只能用非type-safe的方式建,否則compiler是不會過的
08/30 20:23, 3F
文章代碼(AID): #1GFZzSrB (java)
文章代碼(AID): #1GFZzSrB (java)