I'm trying to write a server, which tracks its clients by a uniquely-generated ID using a HashMap<ClientID,Client>. The idea is, if I'm an admin and I want to boot somebody off the server, I look up the appropriate ClientID (which is really just a String; only difference is the ClientID class does the work of ensuring that no two clients are ever assigned the same ID) for that client and then enter a command such as "kick 12" (if the ClientID of the person I wanted to kick happened to be 12).
I assumed this would work because I figured that a HashMap was probably backed by internal use of the hashCode() method inherited from Object, and I designed the ClientID class in a way that would support the necessary lookup operations, assuming that's true. But apparently, it's not true - two keys with the same hashcodes are evidently not considered to be the same key in a HashMap (or HashSet).
I've created a simple example using HashSet to illustrate what I want to do:
import java.lang.*;
import java.io.*;
import java.util.*;
class ClientID {
private String id;
public ClientID(String myId)
{
id = myId;
}
public static ClientID generateNew(Set<ClientID> existing)
{
ClientID res = new ClientID("");
Random rand = new Random();
do {
int p = rand.nextInt(10);
res.id += p;
} while (existing.contains(res));
return res;
}
public int hashCode()
{
return (id.hashCode());
}
public boolean equals(String otherID)
{
return (id == otherID);
}
public boolean equals(ClientID other)
{
return (id == other.id);
}
public String toString()
{
return id;
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
HashSet<ClientID> mySet = new HashSet<ClientID>();
ClientID myId = ClientID.generateNew(mySet);
mySet.add(myId);
String input;
do {
System.out.println("List of IDs/hashcodes in the set: ");
for (ClientID x: mySet)
System.out.println("\t" + x.toString() + "\t" + x.hashCode());
System.out.print("\nEnter an ID to test if it's in the set: ");
input = in.readLine();
if (input == null)
break;
else if (input.length() == 0)
continue;
ClientID matchID = new ClientID(input);
if (mySet.contains(matchID))
System.out.println("Success! Set already contains that ID :)");
else {
System.out.println("Adding ID " + matchID.toString() + " (hashcode " + matchID.hashCode() + ") to the set");
mySet.add(matchID);
}
System.out.println("\n");
} while (!input.toUpperCase().equals("QUIT"));
}
}
Using this code, it is impossible (as far as I can tell) to produce the output
Success! Set already contains that ID :)
... Instead, it will just keep adding values to that set, even if the values are duplicates (that is, they are equal with the equals method AND they have the same hashcode). If I'm not communicating this well, run the code for yourself and I think you'll quickly see what I mean... This makes lookups impossible (and it also means the Client.generateNew method does NOT work at all as I intend it to); how do I get around this?