Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java映射<;K、 V>;为get和remove方法获取非类型化参数?_Java_Api_Generics - Fatal编程技术网

为什么Java映射<;K、 V>;为get和remove方法获取非类型化参数?

为什么Java映射<;K、 V>;为get和remove方法获取非类型化参数?,java,api,generics,Java,Api,Generics,我在代码中遇到了一个错误,我使用了错误的键从Java映射中获取了一些我认为是使用Java泛型强类型的东西。当查看Map Javadocs时,许多方法(包括get和remove)都将对象作为参数,而不是类型K(对于定义为Map的Map)。为什么会这样?这是一个很好的理由还是一个API设计缺陷?我认为这是为了与旧版本的Map接口向后兼容。不幸的是,情况是这样的。但是,如果您是对的,那么采用正确的类型会更好。因为如果传递给get方法的对象等于映射中存储的任何键,则映射将返回一个值。Equal并不意味着

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

我认为这是为了与旧版本的Map接口向后兼容。不幸的是,情况是这样的。但是,如果您是对的,那么采用正确的类型会更好。

因为如果传递给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));
LinkedList k1=新建LinkedList();
k1.添加(10);
ArrayList k2=新的ArrayList();
k2.添加(10);
Map Map=newhashmap();
地图放置(k1,“foo”);
System.out.println(map.get(k2));

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

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

如果将
get()。这将使通配符映射实际上无法使用

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

下面是一个代码示例,如果
get
被声明为
get(T键)
,则该代码不可能实现:


public static Map intersect(Map一些IDE对此情况有一个警告。虽然问题不是完全重复的,但可以在另一个问题的答案中找到答案。我认为我应该在我的IDE中设置警告。:)这些方法不能将K作为泛型类型,因为K没有覆盖映射的所有有效键类型(见我的答案)-1:如果强制搜索键与映射键的类型相同也不会更好-这是一个常见的用例,但肯定不是唯一的一个。我已经实现了具有复杂键的映射,并且可以使用简单字符串或其他降低复杂度的键进行搜索。YUK!我强烈不同意这种说法-我认为如果您想要使用不同类型可以用作有效键的用例,然后创建覆盖或额外方法来约束使用。这样,您就有了一个强类型、明确记录的接口来指示预期的使用。任何使用对象参数的泛型都表明IMO的设计很差。这种设计将自己留给poten非常危险的情况。虽然这在理论上可能是正确的,但使用equals()和hashcode()创建多个类将是一种极其丑陋的黑客行为以这种方式工作的实现。在我看来,这些方法不太可能被定义为将对象作为参数,这样人们就可以编写这样的代码。@Luke Hutterman:看一下列表接口的equals方法的文档。它的合同规定,如果两个列表都是列表和它们的ele,那么它们应该是相等的无论列表的类别如何,元素的顺序都是一样的。集合和映射接口也是一样的即使你觉得很难看,这也正是API文档中定义映射接口和对象#equals方法的方式。在向映射接口添加泛型时,必须注意不要改变已定义的inter的行为face方法。强制get方法的参数实际上与泛型K类型属于同一类型将是对接口定义的不向后兼容更改。@newacct:在该示例中,值具有相同的类型-java.util.List-即使不是同一类。这足以使用约束更严格的get。您可以想出更奇怪的场景,其中有效键共享的类型不比Object更具体,但我无法想象它们是我希望实现的场景!@newacct:但如果您声明映射,您可以使用任何类型的列表。您的示例(不同列表实现之间的平等性)只有当有人声明一个映射并随后尝试使用LinkedList调用get()时,这才是一个问题;同样,这是一个非常难看的黑客行为。通过将变量推入一个具有其自身类型参数的方法中,您可以解决这个问题-例如
void duplicateFirst(List l){T first=l.get(0);l.add(0,first);}
。但在这种情况下,我很难理解为什么地图实际上并非毫无用处。
Map
可能相对无用,但同样的论点适用于,例如,
地图
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;
}