【问题标题】:ConcurrentHashMap - Odd behaviourConcurrentHashMap - 奇怪的行为
【发布时间】:2013-07-10 08:19:32
【问题描述】:

谁能告诉我这段代码出了什么问题?我要拔头发了!

如果我使用 HashMap 而不是 ConcurrentHashMap 没有任何问题。代码使用JDK 5.0编译

public class MapTest {
    public Map<DummyKey, DummyValue> testMap = new ConcurrentHashMap<DummyKey, DummyValue>();

  public MapTest() {
      DummyKey k1 = new DummyKey("A");
      DummyValue v1 = new DummyValue("1");
      DummyKey k2 = new DummyKey("B");
      DummyValue v2 = new DummyValue("2");

      testMap.put(k1, v1);
      testMap.put(k2, v2);
  }

  public void printMap() {
      for(DummyKey key : testMap.keySet()){
          System.out.println(key.getKeyName());
          DummyValue val = testMap.get(key);
          System.out.println(val.getValue());
      }
  }

  public static void main(String[] args){
      MapTest main = new MapTest();
      main.printMap();
  }


  private static class DummyKey {
      private String keyName = "";

      public DummyKey(String keyName){
        this.keyName = keyName;
      }

      public String getKeyName() {
        return keyName;
      }

      @Override
      public int hashCode() {
        return keyName.hashCode();
      }

  @Override
      public boolean equals(Object o) {
         return keyName.equals(o);
      }
  }

  private static class DummyValue {
      private String value = "";

      public DummyValue(String value){
         this.value = value;
      }

      public String getValue() {
        return value;
      }
   }
}

这是输出:

B
Exception in thread "main" java.lang.NullPointerException
at test.MapTest.printMap(MapTest.java:27)
at test.MapTest.main(MapTest.java:34)

【问题讨论】:

  • 嗯,我会加入。第 27 行:System.out.println(val.getValue());

标签: java concurrency concurrenthashmap


【解决方案1】:

DummyKey.equals 方法实现不正确,因为 testMap.get(key) 总是返回 null。试试这个

public boolean equals(Object o) {
    if (o instanceof DummyKey) {
        DummyKey other = (DummyKey) o;
        return keyName == null ? other.keyName == null : keyName.equals(other.keyName);
    }
    return false;
}

hashCode 也需要稍作改动才能与 equals 保持一致

public int hashCode() {
    return keyName == null ? 0 : keyName.hashCode();
}

【讨论】:

  • 旧版本的 DummyKey equals 在将对象与自身进行比较时会返回 false,这会破坏 equals 契约,从而阻止 HashMap 找到已放入映射中的键。跨度>
  • 请注意,您还应该更改 hashCode 以计算空值。当前的 hashCode 可能会导致 NullPointerException
【解决方案2】:

问题出在你的equalsDummyKey

当您调用 DummyValue val = testMap.get(key); 时,hashcode 函数会找到匹配项(k1keykeynamekey 相同,它们的哈希码也相同)。然而,equals 返回 false,因为 k1.keyname 等于 "A" 不等于 key 本身,它实际上是 DummyValue 类型:你没有正确比较!

因此,你需要修改你的equals函数:

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    DummyKey other = (DummyKey) obj;
    if (keyName == null) {
        if (other.keyName != null)
            return false;
    } else if (!keyName.equals(other.keyName))
        return false;
    return true;
}

【讨论】:

    【解决方案3】:

    请注意,如果您更改 hashCode(),那么您也必须更改 equals()。否则,您将遇到问题。如果 equals() 对两个项目返回 true,那么它们的 hashCode() 值必须相等!相反不是必需的,但对于更好的散列性能更可取。这是equals()和hashCode()的一个实现。

    提示:如果您使用 eclipse,您可以利用其源代码生成功能为您创建正确的 hashCode() 和 equals() 方法。您唯一需要做的就是选择标识对象的实例变量。要在 eclipse 中这样做,当你的源代码打开时,转到顶部的选项卡并选择“source”,然后选择“Generate hashCode() and equals()...”

      @Override
      public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
    
        return result;
      }
    
      Override
      public boolean equals(Object other) {
         if(this == other) return true; //for optimization
         if(! other instanceof this) return false; //also covers for when other == null
         return this.keyName == null ? other.keyName == null : this.keyName.equals(other.keyName);
      }
    

    【讨论】:

      【解决方案4】:

      正如其他人所指出的,问题在于您覆盖哈希码和等于的方式。 两个选项:1)只需删除哈希码和等号就可以了 2)我让eclipse生成hashcode和equals的源代码,它工作正常。这就是我的日食为我带来的结果:

      @Override
          public int hashCode() {
              final int prime = 31;
              int result = 1;
              result = prime * result
                      + ((keyName == null) ? 0 : keyName.hashCode());
              return result;
          }
      
          @Override
          public boolean equals(Object obj) {
              if (this == obj)
                  return true;
              if (obj == null)
                  return false;
              if (getClass() != obj.getClass())
                  return false;
              DummyKey other = (DummyKey) obj;
              if (keyName == null) {
                  if (other.keyName != null)
                      return false;
              } else if (!keyName.equals(other.keyName))
                  return false;
              return true;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-08
        • 2015-07-20
        • 2010-10-03
        • 2021-07-12
        • 2013-10-04
        相关资源
        最近更新 更多