有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java:通用过滤器映射函数

我正在尝试开发一个通用函数来过滤地图

到目前为止,我掌握的代码是:

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中发现以下错误。放

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()似乎起到了作用


共 (3) 个答案

  1. # 1 楼答案

    这条线

    Map<?, ?> filteredAttrs = Map.class.newInstance();
    

    应该抛出实例化异常,因为Map是一个接口,除非您实现了自己的名为Map的类

  2. # 2 楼答案

    无法实例化映射,因为它是一个接口。不要使用?,因为它一开始会造成混乱

    public static <T, K> Map<T, K> filterAttrs(Map<T, K> args, T... unless) {
        Map<T, K> filteredAttrs;
    
        filteredAttrs = new HashMap<T, K>();
        Arrays.sort(unless);
        for (T o : args.keySet()) {
            if (Arrays.binarySearch(unless, o) < 0) {
                filteredAttrs.put(o, args.get(o));
            }
        }
    
        return filteredAttrs;
    }
    

    你有一行什么都不做,所以我删除了它:-

    String attr = o.toString();
    
  3. # 3 楼答案

    这段代码的问题是,类型系统阻止您将对象放入Map中,该对象的键类型为?。这是因为,如果密钥类型是?,编译器不知道映射中实际存储的是什么——它可能是Object,或者Integer,或者List<Object>——因此它无法确认您试图添加到映射中的内容实际上是正确的类型,并且不会在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作为键和值放入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是一个接口,而不是一个类,因此尝试使用newInstance创建它的实例将无法正常工作。要解决这个问题,您可以显式地指定映射的类型(正如我在上面的代码中所做的),或者获取参数的类:

    Map<K, V> filteredAttrs = args.getClass().newInstance();
    

    当然,这也不能保证有效,尽管集合的一般约定是所有集合都应该有一个无参数构造函数

    希望这有帮助