简体   繁体   English

ConcurrentHashMap - 奇怪的行为

[英]ConcurrentHashMap - Odd behaviour

Can anyone let me know what goes wrong in this piece of code? 谁能让我知道这段代码出了什么问题? I'm pulling my hair out! 我把头发拉出来!

There isn't any problem if I use HashMap instead of ConcurrentHashMap. 如果我使用HashMap而不是ConcurrentHashMap没有任何问题。 The code is compiled with JDK 5.0 代码使用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;
      }
   }
}

This is the output: 这是输出:

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

DummyKey.equals method implementation is incorrect, due to that testMap.get(key) always returns null. DummyKey.equals方法实现不正确,因为testMap.get(key)始终返回null。 Try this 尝试这个

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 also needs a little change to be consistent with equals hashCode也需要一点改变才能与equals保持一致

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

The problem comes from your equals in DummyKey . 这个问题是从equalsDummyKey

When you call DummyValue val = testMap.get(key); 当你调用DummyValue val = testMap.get(key); , the hashcode function finds a match (both keyname of k1 and key are the same and so are their hashcode). 中, hashcode函数找到一个匹配(两个keynamek1key是相同的,所以他们的哈希码)。 Yet equals returns false because k1.keyname is equal to "A" which is not equal to key itself, which is actually of type DummyValue : you are not comparing properly! 然而,equals返回false,因为k1.keyname等于"A" ,它不等于key本身,实际上是DummyValue类型:你没有正确比较!

Therefore, you need to modify your equals function: 因此,您需要修改您的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;
}

Please note that if you change hashCode(), then you must change equals() as well. 请注意,如果更改hashCode(),则还必须更改equals()。 Otherwise, you will run into problems. 否则,你会遇到问题。 If equals() returns true for two items, then their hashCode() value must be equal! 如果equals()为两个项返回true,那么它们的hashCode()值必须相等! The opposite is not required but preferable for better hashing performance. 相反的不是必需的,但更好的散列性能。 Here is an implementation of equals() and hashCode(). 这是equals()和hashCode()的实现。

HINT: if you are using eclipse, you can utilize its source generation capability to create the correct hashCode() and equals() method for you. 提示:如果您使用的是eclipse,则可以利用其源代码生成功能为您创建正确的hashCode()和equals()方法。 The only thing you need to do is to pick the instance variables that identify the object. 您唯一需要做的就是选择标识对象的实例变量。 To do so in eclipse, while your source code is open, go to the tabs in the top and choose "source", then choose "Generate hashCode() and 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);
  }

As others have pointed, the problem lies in the way you override hashcode and equals. 正如其他人指出的那样,问题在于你覆盖hashcode和equals的方式。 Two options : 1) Just remove the hashcode and equals and it works fine 2) I let eclipse generate the source for hashcode and equals and it works fine. 两个选项:1)只需删除哈希码和等号,它工作正常2)我让eclipse生成哈希码和等号的源,它工作正常。 This is what my eclipse belted out for me : 这就是我的日食对我而言:

@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;
    }

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

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