简体   繁体   English

Map containsKey返回false

[英]Map containsKey returns false

My got a HashMap data: 我有一个HashMap数据:

Map<CharSequence, MyObject> dataMap = GET_FROM_SOME_WHERE

There is a key in the dataMap which is a CharSequence type with value "company.name" dataMap有一个键是CharSequence类型,其值为“company.name”

But the following code returns me false : 但是下面的代码返回false

String field = "company.name";
dataMap.containsKey(field); //This return me false

I somehow feel that it is because my field variable is a String object while the key in HashMap is CharSequence . 我不知何故觉得这是因为我的field变量是一个String对象,而HashMap中的键是CharSequence That's why it returns me false. 这就是为什么它让我失意。

If my guess is correct, then how to get rid of it? 如果我的猜测是正确的,那么如何摆脱它呢? I need the above code returns me true. 我需要上面的代码返回我的真实。 I am sure the key "company.name" is in that map data as key. 我确信关键字“company.name”在该地图数据中是关键。

The Java API Spec has this to say on the subject: Java API Spec对此主题有这样的说法:

'Each object may be implemented by a different class, and there is no guarantee that each class will be capable of testing its instances for equality with those of the other. '每个对象可以由不同的类实现,并且不能保证每个类都能够测试其实例与另一个类的实例是否相等。 It is therefore inappropriate to use arbitrary CharSequence instances as elements in a set or as keys in a map.' 因此,将任意CharSequence实例用作集合中的元素或映射中的键是不合适的。

为什么不放

CharSequence field = "company.name";

Are you putting StringBuffers into a HashMap? 你是否将StringBuffers放入HashMap? Because that is not going to work, since StringBuffer does not define a hashCode method. 因为这不起作用,因为StringBuffer没有定义hashCode方法。 It inherits hashCode from java.lang.Object which uses the object's identity as hash code. 它从java.lang.Object继承hashCode,它使用对象的标识作为哈希码。

String on the other hand calculates hash code from the actual string data. 另一方面,String根据实际的字符串数据计算哈希码。

Edit: StringBuffer doesn't implement equals() method either, so it won't work at all like one would expect. 编辑:StringBuffer也没有实现equals()方法,所以它根本不会像人们期望的那样工作。 (new StringBuffer("1")).equals(new StringBuffer("1")) -> false. (new StringBuffer(“1”))。equals(new StringBuffer(“1”)) - > false。

In order for this to work, the implementation of CharSequence inside your map must recognize String s in checking for equality, produce identical hash codes with the String , and return true when compared for equality to a string with the same value (ie equals should work from both sides). 为了实现这一点,在映射中实现CharSequence必须在检查相等性时识别String ,使用String生成相同的哈希码,并在将相等性与具有相同值的字符串进行比较时返回true (即equals应该工作来自双方)。 This is not possible unless the implementation of CharSequence is actually a String . 除非CharSequence的实现实际上是String否则这是不可能的。

One way to address this is converting the Map<CharSequence,MyObject> to a Map<String,MyObject> . 解决此问题的一种方法是将Map<CharSequence,MyObject>转换为Map<String,MyObject> Iterate through the entry set of the original map, and put the data into a copy that uses the String as the key, like this: 迭代原始映射的入口集,并将数据放入使用String作为键的副本中,如下所示:

Map<String,MyObject> copy = new HashMap<String,MyObject>();
for (Map.Entry<CharSequence,MyObject> e : dataMap.entrySet()) {
    copy.put(e.getKey().toString(), e.getValue());
}

Using Collection can be quite tricky sometimes. 使用Collection有时候会非常棘手。

The way that a Map.containsKey() works is by examining object equality by calling the .equals() method of your 'key' objects. Map.containsKey()的工作方式是通过调用“key”对象的.equals()方法来检查对象的相等性。 So, if you put things in the map via a StringBuffer - which also implements CharSequence - but try to ask whether the key exists in the map but providing a String as the key, you are really challenging the Collections framework. 因此,如果您通过StringBuffer (也实现CharSequence)将事物放入地图中,但是尝试询问密钥是否存在于地图中但是提供了String作为密钥,那么您确实在挑战集合框架。 This can be shown by below example: 这可以通过以下示例显示:

Map<CharSequence, Integer> dataMap = new HashMap<CharSequence, Integer>();
StringBuffer sb = new StringBuffer();
sb.append("company.name");
CharSequence cs = sb;
dataMap.put(cs, 123);

String k = "company.name";
// Below prints a 'false'
System.out.println(dataMap.containsKey(k));

Accordingly, my advice is to always use the same type of objects as key entries in a collection (not just Map). 因此,我的建议是始终使用相同类型的对象作为集合中的键条目(不仅仅是Map)。 In this case, perhaps you can also define your Map as 在这种情况下,也许您也可以将Map定义为

Map<String, MyObject>

Possible reason is that equals() method is used in your map. 可能的原因是在地图中使用了equals()方法。 Another is hashCode() is used. 另一个是使用hashCode() If key in map isn't a String, it can give you another values by these methods. 如果map中的键不是String,它可以通过这些方法为您提供其他值。

If you are getting map somewhere outside and cannot control it, iteration over key set seems to be the only approach here. 如果你在某个地方得到地图并且无法控制它,那么迭代按键设置似乎是唯一的方法。 Otherwise I would suggest to change map to Map<String, MyObject> 否则我建议将map更改为Map<String, MyObject>

public static void main(String[] args) {
    Map<CharSequence, String> dataMap = new HashMap<>();
    dataMap.put(new StringBuilder("company.name"), "AAA");
    System.out.println(dataMap.containsKey("company.name"));
    System.out.println(mapContainsKeyNamed("company.name", dataMap));
}

static boolean mapContainsKeyNamed(String key, Map<CharSequence, ?> map) {
    for (CharSequence cs : map.keySet()) {
        if (key.equals(cs.toString())) {
            return true;
        }
    }
    return false;
}

output: 输出:

false
true

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM