【问题标题】:Why does HashMap get() method returns null after modifying an inserted object? [duplicate]为什么HashMap get()方法修改插入对象后返回null? [复制]
【发布时间】:2016-03-17 18:56:28
【问题描述】:

我实现了overriding equals and hashCode correctly。在下面的代码中,当我打印出 map 和 num1 时,我可以在控制台中看到它们都有更新的 hashCode()。但是当我试图把它从地图中取出时,它说它是空的。有人可以帮助解释为什么 .get() 方法找不到它吗?

class Phone {

    int number;

    Phone(int number) {this.number = number;}

    public int hashCode() {
        return number;
    }

    public boolean equals(Object o) {
        if (o != null && o instanceof Phone)
            return (number == ((Phone)o).number);
        else
            return false;
    }

    public static void main(String args[]) {
        Map<Phone, String> map = new HashMap<>();
        Phone num1 = new Phone(2500);
        map.put(num1, "John");
        num1.number = 100;

        System.out.println(map);
        System.out.println(num1);
        System.out.println(map.get(num1)); // why does it print null
    }
}

【问题讨论】:

  • 通知num1.number = 100;
  • 开发人员:这不是一个坏问题,很可能是一个很常见的错误。你应该支持这个问题,因为它可能对其他人有帮助。
  • @pczeus 它可能被否决了,因为这是一个常见问题,并且网站上已经有多个已回答的问题(我上面链接的问题可能在输入此问题的标题时已经提出)。

标签: java hashmap hashcode


【解决方案1】:

您已经创建了一个问题,因为您在将密钥放入 Map 后修改了密钥,该密钥根据数字从您的 hashcode 方法中得到散列。

清理一下你的代码。更具体地说,使数字不可变,并且仅通过公共 getter 方法提供对数字的访问权限。您不应该允许 Map 中的键是可变的。

public class MyNumber {
    private int number;

    public MyNumber(int number) {
        this.number = number;
    }

    public int getNumber(){
        return number;
    }

    @Override
    public int hashCode() {
        return number;
    }

    @Override
    public boolean equals(Object o) {
        if (o != null && o instanceof MyNumber) {
            return (number == ((MyNumber) o).number);
        }
        else {
            return false;
        }
    }

    @Override
    public String toString(){
        return this.getClass().getName() + "(" + number + ")";
    }
}

我已将 cmets 添加到您的主类中的代码中:

import java.util.HashMap;
import java.util.Map;

public class OverrideHashCode {

    public void mutableObjectKeys() {
        Map<MyNumber, String> map = new HashMap<>();
        MyNumber num1 = new MyNumber(2500);
        map.put(num1, "Shreya");

        System.out.println(map);
        System.out.println(num1);

       //This line was your issue. You placed the MyNyumber in the map
        //The hashcode pulls the number value from MyNumber to hash the entry (2500 )
        //Then you change the value of number
        //num1.getNumber() = 100;
        System.out.println(map);
        System.out.println(num1);

        //This was hashed at 2500, but you changed the MyNumber to 100 - no match
        System.out.println(map.get(num1)); // prints null - not anymore

        //Let's put a second object in the Map
        map.put(new MyNumber(500), "GroovyIsBetter!");

        //When you work with Maps, you are commonly trying to get values out of the map based on the key.
        //In this example, our key's are MyNumber(s)
        //We have made MyNumber.number immutable (which is good).
        //Because you implemented your own hashcode and equals, you can even pull the value out of the map
       //with a new MyNumber object that has the same number value as the original key you placed in the map
        System.out.println("\n" + map.get(new MyNumber(2500)));
        System.out.println(map.get(new MyNumber(500)));

        //Now we can remove one of the keys and recheck
        //Should come up null
        map.remove(new MyNumber(500));
        System.out.println(map.get(new MyNumber(500)));
    }

    public static void main(String... args){
        new OverrideHashCode().mutableObjectKeys();;
    }

【讨论】:

  • 如果你希望number 是不可变的,你应该将它设为final,所以很明显它是故意不可变的。
  • 感谢@pczeus 解释使用地图的行为
【解决方案2】:

它返回null,因为你改变了num1对象的数量,从而改变了它的hashcode。哈希映射使用 hashcode() 来存储和检索对象,因此当您更改它时,您会在错误的位置查找对象,因为它存储在编号为 2500 的位置,但随后您会在位置 100 查找它。那是因为您的哈希码返回数字。希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    • 2017-09-27
    相关资源
    最近更新 更多