我正在尝试开发一个通用函数来过滤 map 。
我目前的代码是:
public static Map<?, ?> filterAttrs(Map<?, ?> args, String... unless) {
Map<?, ?> filteredAttrs = Map.class.newInstance();
Arrays.sort(unless);
for (Object o : args.keySet()) {
if (Arrays.binarySearch(unless, o.toString()) < 0 ) {
filteredAttrs.put(o, args.get(o));
}
}
return filteredAttrs;
}
我在 filteredAttrs.put 中收到以下错误
The method put(capture#5-of ?, capture#6-of ?) in the type Map is not applicable for the arguments (Object, capture#8-of ?)
我不知道如何实例化通用 Map
(我尝试使用 1Map.class.newInstance()`)。
有什么想法吗?
编辑:阅读许多答案后,问题似乎是如何使 filteredAttrs
成为与 args
相同类型的实例。 (Map) args.getClass().newInstance()
似乎可以解决问题。
最佳答案
此代码的问题在于类型系统阻止您将对象放入 Map
中。其 key 类型为 ?
.这是因为如果 key 类型是 ?
,编译器不知道映射中实际存储了什么——它可能是 Object
, 或 Integer
, 或 List<Object>
- 因此它无法确认您尝试添加到 map 的内容实际上是正确的类型并且不会在 Map
中不合适。 .例如,如果您有此方法:
public static void breakMyMap(Map<?, ?> m) {
m.put(new Object(), new Object()); // Won't compile
}
然后编写如下代码:
Map<String, String> myMap = new HashMap<String, String>();
breakMyMap(myMap);
那么如果breakMyMap
中的代码要编译,它会放一对 Object
s 作为键和值放入 Map<String, String>
,打破了所有元素确实是String
的不变量
要解决这个问题,而不是让这个函数在 Map<?, ?>
上工作, 更改函数,以便您有更多关于键和值的类型信息。例如,您可以尝试这样做:
public static <K, V> Map<K, V> filterAttrs(Map<K, V> args, String... unless) {
Map<K, V> filteredAttrs = new HashMap<K, V>();
Arrays.sort(unless);
for (K o : args.keySet()) {
String attr = o.toString();
if (Arrays.binarySearch(unless, o.toString()) < 0 ) {
filteredAttrs.put(o, args.get(o));
}
}
return filteredAttrs;
}
现在编译器知道键类型是K
, 它可以验证 put
不会混淆映射中键的类型。
我应该指出的另一件事是,即使编译成功,您的代码也永远不会工作。原因是行
Map<?, ?> filteredAttrs = Map.class.newInstance();
会在运行时引发异常,因为Map
是一个接口(interface),而不是一个类,因此尝试使用 newInstance
创建它的实例将无法正常工作。要解决此问题,您可以明确指定 map 的类型(正如我在上面的代码中所做的那样),或者获取参数的类:
Map<K, V> filteredAttrs = args.getClass().newInstance();
当然,这也不能保证有效,尽管集合的一般约定是所有集合应该有一个无参数构造函数。
希望这对您有所帮助!
关于Java:通用过滤器映射函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5060057/