Reputation: 167
I know this question will be pretty amateur but, I having trouble understanding why my hashmap will not store or retrieve values when I use the same object instance as a key. My code is as follows
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());
}
}
I am overriding hashcode and equals as follows.
@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);
}
When I try to get the size of the hashmap, it returns as only one. meaning the first insertion into the hashmap was overridden by the second one.
Is it because I am using the same instance of Candidate to insert two values? Is it possible to force hashmap to insert both key,value pairs?
Upvotes: 1
Views: 57
Reputation: 120848
There is a simpler way to do what you want with java-8
btw, simplified example:
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]}
Upvotes: 3
Reputation: 285403
The whole idea behind a Map is that 1) keys are unique -- it holds only one key/value pair for a particular key, and 2) its look up is relatively "cheap".
You've only got one object within your HashMap. Understand that when you add another key, value pair to the map, if the key is the same as a previous item in the map, the previous item is replaced by the new one. If you want to add two or more items, then use different keys, or create a Map that holds a List<...>
of objects as its value. e.g.,
HashMap<Candidate, List<String>>
In this situation, you would first check to see if the Map holds a Candidate item, and if so, add a new String to its list. If not, then add the new Candidate with a new ArrayList<String>
value. Usually I use a method for just this purpose, something like:
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);
}
}
And yes, as d.j.brown states in comment, fix your equals method to avoid a class cast exception.
Something like so:
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);
}
}
Upvotes: 3
Reputation: 3324
Either use
Map<Candidate, List<String>>
orMultimap
: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.htmlUpvotes: 0