我的android项目中有一个适配器,它接受一个可重复使用的地图,为简单起见,它保留了一组数据。
private Entry<String, String>[] mData;
public MyAdapter(@NonNull Map<String, String> data) {
mData = (Entry<String, String>[]) data.entrySet().toArray();
}
现在我想让它更有效率并摆脱未经检查的警告,所以我改为使用特定的数组类型
mData = data.entrySet().toArray( new Entry<String, String>[ data.size() ] );
但new Entry<String, String>[ data.size() ]
部分现已标记为&#34; 通用数组创建&#34;没有进一步的信息。 为什么这是非法的?
我知道Java有类型擦除,并且泛型导致不同类型(例如解释here),但上面的代码行似乎对我来说应该是合法的。
答案 0 :(得分:1)
为什么这是非法的?
因为数组是协变的。假设您能够编译以下代码:
Entry<String, String>[] array = new Entry<String, String>[ isoMap.size() ];
Object[] objArray = array;
// Does not throw an ArrayStoreException.
objArray[0] = new AbstractMap.SimpleEntry<>(Integer.valueOf(0), Integer.valueOf(0));
String key = array[0].getKey();
在运行时,赋值不会抛出ArrayStoreException
,因为AbstractMap.SimpleEntry
(AbstractMap.SimpleEntry<Integer, Integer>
的运行时类型)与Map.Entry
是协变的(运行时类型为{ {1}}) - 但是当您尝试执行最后一行时,它会因Entry<String, String>
而失败,因为它们的密钥是ClassCastException
,而不是Integer
。
但是,您现在必须担心每个元素可能是错误的类型 - 给定String
的引用,您无法准确知道数组的初始化方式或更新,因此以错误的方式访问任何给定元素可能会导致运行时异常。
(当我说“错误的方式”时,我用Entry<String, String>[]
之类的东西来约束String key = array[0].getKey()
- 所有对象都有array[0].toString()
方法,所以不会尝试转换)。
避免这种情况最安全的方法就是使通用数组的创建非法。
请注意,这与非泛型但协变数组的情况不同:
toString()
因为该赋值会抛出String[] array = new String[1];
Object[] objArray = array;
// Throws an ArrayStoreException.
objArray[0] = Integer.valueOf(0);
,所以错误类型的值永远不会添加到数组中。
因此,虽然在尝试将值放入数组时仍然需要担心ArrayStoreException
,但在从数组中读取值时,您不必担心ArrayStoreException