有 Java 编程相关的问题?

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

api为什么Java Map<K,V>为get和remove方法使用非类型化参数?

我在代码中遇到了一个错误,我使用了错误的键从Java映射中获取了一些我认为是使用Java泛型强类型的东西。当查看Map Javadocs时,许多方法(包括get和remove)都将对象作为参数,而不是类型K(对于定义为Map的Map)。为什么会这样?这是一个很好的理由还是一个API设计缺陷


共 (3) 个答案

  1. # 1 楼答案

    因为如果传递给get方法的对象等于映射中存储的任何键,则映射将返回一个值。Equal并不意味着它们必须是相同的类型,而是键和传递对象的Equal方法以这样的方式实现,即不同的对象类型被相互识别为相等

    当然,删除方法也是如此


    有效代码示例,如果get方法只允许K类型的参数,则会中断(而不是编译):

    LinkedList<Number> k1 = new LinkedList<Number>();
    k1.add(10);
    
    ArrayList<Integer> k2 = new ArrayList<Integer>();
    k2.add(10);
    
    Map<LinkedList<Number>, String> map = new HashMap<LinkedList<Number>, String>();
    
    map.put(k1, "foo");
    System.out.println(map.get(k2));
    
  2. # 2 楼答案

    我认为这是为了向后兼容旧版本的地图界面。不幸的是,情况就是这样。不过,你是对的,如果选择正确的类型会更好

  3. # 3 楼答案

    这样做的目的是,如果类型参数是通配符,则仍然可以调用这些方法

    若您有一个Map<?, ?>,Java将不允许您调用任何以泛型类型作为参数声明的方法。这可以防止您违反类型约束,例如,您不能使用错误的类型调用put(key, value)

    如果get()被定义为get(K key)而不是当前的get(Object key),那么它也会因为同样的规则而被排除。这将使通配符映射实际上无法使用

    理论上,这同样适用于remove(),因为删除对象也永远不会违反类型约束

    下面是一个如果get被声明为get(T key)就不可能实现的代码示例:

    public static <K,V> Map<K, V> intersect(Map<? extends K, ? extends V> m1, Map<? extends K, ? extends V> m2) {
        Map<K,V> result = new HashMap<K, V>();
        for (Map.Entry<? extends K, ? extends V> e1 : m1.entrySet()) {
            V value = m2.get(e1.getKey()); // this would not work in case of Map.get(K key)
            if (e1.getValue().equals(value)) {
                result.put(e1.getKey(), e1.getValue());
            }
        }
        return result;
    }
    

    e1.getKey()返回某个未知子类型K(由m1使用的子类型)的对象,但m2使用了可能不同的K子类型。如果Map.get()被声明为get(K key),则不允许这种用法