作者awert ( )
看板java
标题Re: [J2SE] 宣告 Set<String> edge[] 出了错误讯息
时间Thu Aug 30 00:12:09 2012
※ 引述《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
1F:推 tailsice:感谢大大的指点,我对泛型有了更深的认识。 08/30 10:03
2F:→ sbrhsieh:compiler 没有不准这麽写,只是罗唆一点,提醒要注意。 08/30 15:14
3F:→ awert:只能用非type-safe的方式建,否则compiler是不会过的 08/30 20:23