即使重写哈希码后,HashMap也无法检索这两个值。等于同一个对象

时间:2017-11-23 14:20:51

标签: java hashmap hashcode

我知道这个问题会非常业余,但是,当我使用相同的对象实例作为键时,我无法理解为什么我的hashmap不会存储或检索值。我的代码如下

public class Candidate {

    private  String id;
    private  String name;

    public Candidate (String id, String name){
        this.id = id;
        this.name = name;
    }

    public static void main(String args[]){
        Candidate cad = new Candidate("101","hari");

        HashMap<Candidate,String> mp = new HashMap<Candidate,String>();
        mp.put(cad, "sachin");
        mp.put(cad, "shewag");

        for(Candidate cand : mp.keySet()){
            System.out.println(mp.get(cand).toString());
        }
    }

我正在重写hashcode并且等于如下。

@Override 
    public boolean equals(Object obj){
        Candidate cad =(Candidate)obj;
        if(!(obj instanceof Candidate)){
            return false;
        }
        if(cad.id.equals(this.id) && cad.name.equals(this.name)){
            return true;
        }
        return false;
    }

    @Override 
    public int hashCode(){
        return Objects.hash(id, name);
    }

当我尝试获取hashmap的大小时,它只返回一个。这意味着第二次插入到hashmap中的第一次插入。

是因为我使用相同的Candidate实例来插入两个值吗?是否可以强制hashmap插入键值对?

3 个答案:

答案 0 :(得分:3)

Map背后的整个想法是1)键是唯一 - 它只保存一个特定键的键/值对,2)它的查找相对“便宜”。

你的HashMap中只有一个对象。了解当您向地图添加另一个键值对时,如果该键与地图中的上一个项目相同,则前一个项目将由新的替换。如果要添加两个或更多项,则使用不同的键,或创建一个包含List<...>个对象作为其值的Map。如,

HashMap<Candidate, List<String>>

在这种情况下,您首先要检查Map是否包含Candidate项,如果是,则在其列表中添加一个新String。如果没有,则添加具有新ArrayList<String>值的新候选者。通常我会使用一种方法,例如:

public static void put(Candidate cand, String text) {
    if (newMap.containsKey(cand)) {
        newMap.get(cand).add(text);
    } else {
        List<String> list = new ArrayList<>();
        list.add(text);
        newMap.put(cand, list);
    }
}

是的,正如d.j.brown在注释中所述,修复你的equals方法以避免类强制转换异常。

像这样:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class MyCandidateTest {
    private static Map<Candidate, List<String>> newMap = new HashMap<>();

    public static void main(String args[]) {
        Candidate cad = new Candidate("101", "hari");

        put(cad, "Foo");
        put(cad, "Bar");

        for (Candidate cand : newMap.keySet()) {
            System.out.println(newMap.get(cand).toString());
        }
    }

    public static void put(Candidate cand, String text) {
        if (newMap.containsKey(cand)) {
            newMap.get(cand).add(text);
        } else {
            List<String> list = new ArrayList<>();
            list.add(text);
            newMap.put(cand, list);
        }
    }

}

public class Candidate {

    private String id;
    private String name;

    public Candidate(String id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {
        // Candidate cad =(Candidate)obj; // !! no
        if (!(obj instanceof Candidate)) {
            return false;
        }
        Candidate cad = (Candidate) obj; // !! yes
        if (cad.id.equals(this.id) && cad.name.equals(this.name)) {
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
}

答案 1 :(得分:3)

有一种更简单的方法可以使用java-8 btw做简单的例子:

    HashMap<String, List<String>> mp = new HashMap<>();

    List<String> list = Arrays.asList("aa", "aa", "bb", "bb");

    for (String s : list) {
        mp.computeIfAbsent(s, k -> new ArrayList<>()).add("c");
    }

    System.out.println(mp); // {bb=[c, c], aa=[c, c]}

答案 2 :(得分:0)

使用

  • Map<Candidate, List<String>>
  • 一个很好的第三方替代方案,例如Google的Multimapcppreference