如何在Java中实例化映射数组?

2022-09-01 00:02:08

我可以使用泛型声明一个映射数组来指定映射类型:

private Map<String, Integer>[] myMaps;

但是,我无法弄清楚如何正确实例化它:

myMaps = new HashMap<String, Integer>[count]; // gives "generic array creation" error
myMaps = new HashMap[count]; // gives an "unchecked or unsafe operation" warning
myMaps = (Map<String, Integer>[])new HashMap[count]; // also gives warning

如何在不收到编译器错误或警告的情况下实例化此映射数组?

更新:

谢谢大家的回复。我最终选择了列表建议。


答案 1

严格来说,这不是你问题的答案,但你有没有考虑过使用一个代替?List

List<Map<String,Integer>> maps = new ArrayList<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());

似乎工作得很好。

请参阅 Java 理论和实践:泛型 gotchas,详细了解为什么不鼓励将数组与泛型混合。

更新:

正如Drew在注释中提到的,使用“集合”界面而不是可能更好。如果您需要更改为 的 、或 的其他子接口之一,这可能会派上用场。示例代码:ListSetCollection

Collection<Map<String,Integer>> maps = new HashSet<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());

从这个起点开始,您只需更改为 、 或 实现 的任何其他类。HashSetArrayListPriorityQueueCollection


答案 2

您无法安全地创建泛型数组。有效的Java第2版详细介绍了泛型一章。从第119页的最后一段开始:

为什么创建泛型数组是非法的?因为它不是类型安全的。如果它是合法的,则编译器在其他正确程序中生成的强制转换可能会在运行时失败,并带有 .这将违反泛型类型系统提供的基本保证。ClassCastException

若要更具体地说明这一点,请考虑以下代码片段:

// Why generic array creation is illegal - won't compile!
List<String>[] stringLists = new List<String>[1]; // (1)
List<Integer> intList = Arrays.asList(42); // (2)
Object[] objects = stringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)

让我们假设创建泛型数组的第 1 行是合法的。第 2 行创建并初始化包含单个元素的 。第 3 行将数组存储到数组变量中,这是合法的,因为数组是协变的。第 4 行将 存储到数组的唯一元素中,该元素之所以成功,是因为泛型是通过擦除实现的:实例的运行时类型简单为 ,实例的运行时类型为 ,因此此赋值不会生成 .现在我们遇到了麻烦。我们已将一个实例存储到一个数组中,该数组被声明为仅保存实例。在第 5 行中,我们从此数组的唯一列表中检索唯一元素。编译器会自动将检索到的元素转换为 ,但它是一个 ,所以我们在运行时得到一个。为了防止这种情况发生,第 1 行(创建泛型数组)会生成编译时错误。List<Integer>List<String>ObjectList<Integer>ObjectList<Integer>ListList<String>[]List[]ArrayStoreExceptionList<Integer>List<String>StringIntegerClassCastException

由于数组和泛型不能很好地组合(以及其他原因),因此通常最好使用对象(特定对象)而不是数组。CollectionList