1

我得到了一个HashMap数据:

Map<CharSequence, MyObject> dataMap = GET_FROM_SOME_WHERE

其中有一个键dataMapCharSequence值为“company.name”的类型

但以下代码返回false

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

我不知何故觉得这是因为我的字段变量是一个String对象,而 HashMap 中的键是CharSequence. 这就是为什么它返回我的错误。

如果我的猜测是正确的,那么如何摆脱它?我需要上面的代码返回 true。我确定键“company.name”在该地图数据中作为键。

4

6 回答 6

4

Java API 规范在这个问题上有这样的说法:

'每个对象可以由不同的类实现,并且不能保证每个类都能够测试它的实例是否与其他的实例相等。因此,将任意 CharSequence 实例用作集合中的元素或映射中的键是不合适的。

于 2013-11-01T10:23:42.357 回答
1

为什么不把

CharSequence field = "company.name";
于 2013-11-01T10:11:22.553 回答
1

您是否将 StringBuffers 放入 HashMap 中?因为那是行不通的,因为 StringBuffer 没有定义 hashCode 方法。它从 java.lang.Object 继承 hashCode,java.lang.Object 使用对象的身份作为哈希码。

另一方面,String 从实际的字符串数据中计算哈希码。

编辑: StringBuffer 也没有实现 equals() 方法,所以它根本不会像人们期望的那样工作。(new StringBuffer("1")).equals(new StringBuffer("1")) -> false。

于 2013-11-01T10:17:25.417 回答
1

为了让它工作,CharSequence你的 map 内部的实现必须String在检查相等时识别 s,产生与 相同的哈希码String,并true在比较相等时返回具有相同值的字符串(即equals应该从双方工作)。这是不可能的,除非实现CharSequence实际上是一个String.

解决此问题的一种方法是Map<CharSequence,MyObject>Map<String,MyObject>. 遍历原始映射的入口集,并将数据放入以String为键的副本中,如下所示:

Map<String,MyObject> copy = new HashMap<String,MyObject>();
for (Map.Entry<CharSequence,MyObject> e : dataMap.entrySet()) {
    copy.put(e.getKey().toString(), e.getValue());
}
于 2013-11-01T10:18:12.960 回答
1

使用 Collection 有时会非常棘手。

Map.containsKey() 的工作方式是通过调用“key”对象的 .equals() 方法来检查对象是否相等。因此,如果您通过StringBuffer将内容放入映射中- 它也实现了 CharSequence - 但尝试询问键是否存在于映射中但提供String作为键,那么您确实在挑战 Collections 框架。这可以通过以下示例显示:

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));

因此,我的建议是始终使用与集合中的键条目相同类型的对象(不仅仅是 Map)。在这种情况下,也许您还可以将 Map 定义为

Map<String, MyObject>
于 2013-11-01T10:31:42.170 回答
0

可能的原因是equals()您的地图中使用了该方法。另一个hashCode()是使用。如果 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;
}

输出:

false
true
于 2013-11-01T10:43:44.913 回答