This question already has answers here:
How does a hash table work?
(17 answers)
Closed 1 year ago.
Everyone know hashmap contain unique key. But i want know how it maintain uniqueness?
Suppose we inserted 100 data into the hashmap, After that we insert duplicate key and value in the same hashmap. I know it will override the value. But i want to know it will check all the previous keys which is already stored inside the hashmap then will override new key.
Or if it check previous all keys everytime then it will take more time . So please tell me the correct answer.
You need to know the internal representation of the HashMap.
Actually it is an array of list of key value items, graphically we can represent it as you can see below:
bucket
position
--------
0 NULL
1 --> (K1, V1) --> (K47, V47)
2 NULL
3 NULL
...
54 --> (K89, V89)
...
When you perform a put operation put(key, value) first the code retrieve the hashCode of the key. This value with a module operation is needed to search on the list on the specific bucket.
Then it performs a search element by element on that list performing an equals method to check if the key is already present or not.
If the key is present it replace only the value, if not it will add a new couple key, value at the end of the list.
The pseudo code of the HashMap is similar to the following:
public HashMap {
private List<List<KeyValue<K, V>>> keyValuesBuckets;
public void put(K key, V value) {
int hash = key.hashCode();
int bucketPosition = hash % keyValuesBuckets.size();
for (KeyValue kv : keyValuesBuckets.get(bucketPosition)) {
if (kv.getKey().equals(key)) {
// Key is present change the value and exit
kv.setValue(value);
return;
}
}
// Key is not present
keyValuesBuckets.get(bucketPosition).add(new KeyValue(key, value));
}
Note that the code is not the real code. There is no check on the null values for example, but it gives you the idea on how the equality is checked using both hashCode and equals methods.
To have a more in depth details on how it works start from the definition of [hashCode][1]:
Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap.
and [equals][2]
In the javadoc you can find the contract that equals and hashCode must supply so that a class can be used as a key in a HashMap:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
[1]: https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
[2]: https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-
Take a look at the following image taken from here (https://www.bigocheatsheet.com/)
Hash collections have a O(1) insertion complexity meaning that the operation does not depend on how many data points are already present in the data structure.
As the name suggests keys are hashed into buckets.
If you want to look up a values for key a the key is taken and a hash function employed mapping the value to a specific memory location. There is no need to look up any other value.
The exception are hash collisions which are bound to happen due to dimensionality reduction. After employing the has function, different keys max resolve to the same hash and thus land in the same bucket. In this case other means of checks have to take place (this is the reason why you always have to overwrite hashcode and equals)
Further information about this can be found here: https://stackoverflow.com/a/19691998/3244464
Related
According to this question
how-does-a-hashmap-work-in-java and this
Many Key-Values pairs could be stocked in the same bucket (after calculating the index of the bucket using the hash), and when we call get(key) it looks over the linked list and tests using equals method.
It doesn't sound really optimized to me, doesn't it compare hashCodes of the linked List before the use of equals?
If the answer is NO:
it means most of the time the bucket contains only 1 node, could you explain why ? because according to this logical explanation many differents keys could have the same bucket index.
how the implementation ensure the good distribution of keys ? this probably mean that the bucket table size is relative to the number of keys
And even if the Table Bucket size is equals to the number of keys, how the HashMap hashCode function ensure the good distribution of keys ? isn't a random distribution ?,
could we have more details?
The implementation is open source, so I would encourage you to just read the code for any specific questions. But here's the general idea:
The primary responsibility for good hashCode distribution lies with the keys' class, not with the HashMap. If the key have a hashCode() method with bad distribution (for instance, return 0;) then the HashMap will perform badly.
HashMap does do a bit of "re-hashing" to ensure slightly better distribution, but not much (see HashMap::hash)
On the get side of things, a couple checks are made on each element in the bucket (which, yes, is implemented as a linked list)
First, the HashMap checks the element's hashCode with the incoming key's hashCode. This is because this operation is quick, and the element's hashCode was cached at put time. This guards against elements that have different hashCodes (and are thus unequal, by the contract of hashCode and equals established by Object) but happen to fall into the same bucket (remember, bucket indexes are basically hashCode % buckets.length)
If that succeeds, then, the HashMap checks equals explicitly to ensure they're really equal. Remember that equality implies same hashCode, but same hashCode does not require equality (and can't, since some classes have potentially infinite number of different values -- like String -- but there are only a finite number of possible hashCode values)
The reason for the double-checking of both hashCode and equals is to be both fast and correct. Consider two keys that have a different hashCode, but end up in the same HashMap bucket. For instance, if key A has hashCode=7 and B has hashCode=14, and there are 7 buckets, then they'll both end up in bucket 0 (7 % 7 == 0, and 14 % 7 == 0). Checking the hashCodes there is a quick way of seeing that A and B are unequal. If you find that the hashCodes are equal, then you make sure it's not just a hashCode collision by calling equals. This is just an optimization, really; it's not required by the general hash map algorithm.
To avoid having to make multiple comparisons in linked lists, the number of buckets in a HashMap is generally kept large enough that most buckets contain only one item. By default the java.util.HashMap tries to maintain enough buckets that the number of items is only 75% of the number of buckets.
Some of the buckets may still contain more than one item - what's called a "hash collision" - and other buckets will be empty. But on average, most buckets with items in them will contain only one item.
The equals() method will always be used at least once to determine if the key is an exact match. Note that the equals() method is usually at least as fast as the hashCode() method.
A good distribution of keys is maintained by a good hashCode() implementation; the HashMap can do little to affect this. A good hashCode() method is one where the returned hash has as random a relationship to the value of the object as possible.
For an example of a bad hashing function, once upon a time, the String.hashCode() method only depended on the start of the string. The problem was that sometimes you want to store a bunch of strings in a HashMap that all start the same - for example, the URLs to all the pages on a single web site - resulting in an inordinately high proportion of hash collisions. I believe String.hashCode() was later modified to fix this.
dosn't it compares hachCodes of the linked List instead of use the
equals
Its not required. hashcode is used to determine the bucket number be it put or get operation. Once you know the bucket number with hashcode and find its a linked list there, then you know that you need to iterate over it and need to check for equality to find exact key . so there is no need of hashcode comparison here
Thats why hashcode should be as unique as as it can be so that its best for lookup.
it means most of the time the bucket contains only 1 node
No . It depend on the uniqueness of hascode. If two key objects have same hashcode but are not equal, then bucket with contain two nodes
When we pass Key and Value object to put() method on Java HashMap, HashMap implementation calls hashCode method on Key object and applies returned hashcode into its own hashing function to find a bucket location for storing Entry object, important point to mention is that HashMap in Java stores both key and value object as Map.Entry in bucket which is essential to understand the retrieving logic.
While retrieving the Values for a Key, if hashcode is same to some other keys, bucket location would be same and collision will occur in HashMap, Since HashMap use LinkedList to store object, this entry (object of Map.Entry comprise key and value ) will be stored in LinkedList.
The good distribution of the Keys will depend on the implementation of hashcode method. This implementation must obey the general contract for hashcode:
If two objects are equal by equals() method then there hashcode returned by hashCode() method must be same.
Whenever hashCode() mehtod is invoked on the same object more than once within single execution of application, hashCode() must return same integer provided no information or fields used in equals and hashcode is modified. This integer is not required to be same during multiple execution of application though.
If two objects are not equals by equals() method it is not require that there hashcode must be different. Though it’s always good practice to return different hashCode for unequal object. Different hashCode for distinct object can improve performance of hashmap or hashtable by reducing collision.
You can visit this git-hub repository "https://github.com/devashish234073/alternate-hash-map-implementation-Java/blob/master/README.md".
You can understand the working the working of HashMap with a basic implementation and examples. The ReadMe.md explains all.
Including some portion of the example here:
Suppose I have to store the following key-value pairs.
(key1,val1)
(key2,val2)
(key3,val3)
(....,....)
(key99999,val99999)
Let our hash algo produces values only in between 0 and 5.
So first we create a rack with 6 buckets numbered 0 to 5.
Storing:
To store (keyN,valN):
1.get the hash of 'keyN'
2.suppose we got 2
3.store the (keyN,valN) in rack 2
Searching:
For searching keyN:
1.get hash of keyN
2.lets say we get 2
3.we traverse rack 2 and get the key and return the value
Thus for N keys , if we were to store them linearly it will take N comparison to search the last element , but with hashmap whose hash algo generates 25 values , we have to do only N/25 comparison. [with hash values equally dispersed]
This question already has answers here:
HashMap is already sorted by key?
(3 answers)
Closed 8 years ago.
Map<Integer,String> m1 = new HashMap<>();
m1.put(5, "gfd");
m1.put(1,"sandy");
m1.put(3, "abc");
m1.put(2, "def");
m1.put(1, "ijk");
m1.put(10, "bcd");
m1.put(0, "ssdfsd");
When I Print the map, the output is {0=ssdfsd, 1=ijk, 2=def, 3=abc, 5=gfd, 10=bcd}.
But, how the output is in sorted order even though I have used HashMap()??
You can easily see this in the implementation. If you look into the source of HashMap.put(), you can see that the hash table index of the object is determined like this:
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
The methods hash() and indexFor() only ensure that there are not too many collisions of hash values and they don't exceed the length of the hash table.
Now if you take a look at Integer.hashCode(), you'll see that the hash is the integer itself:
public int hashCode() {
return value;
}
So the integer which has the value 0 ends up in index 0 of the hash table and so on. At least as long as the hash table is big enough.
The toString() method of HashMap iterates over the hash table and the elements in each index of the hash table. So in your case the order is preserved.
As others mentioned correctly, this behavior is not ensured by implementations of Map. It just works in this special case.
A Map provides you with the interface of storing and retrieving objects into a map with a key attached to them.
What each implementation does internally is fully up to it, including in which order the key/value pairs are stored in the internal structure. See #Seshoumaro's answer for the quote from the javadoc.
HashMap hashes the key (which is an Integer in this case) and uses that hash as an array index. Since the hashCode for Integer is fairly simple to write yourself, it's not surprising that the array indices for each one are in the same order as the key itself.
What all that means is: you shouldnt be surprised that the HashMap is acting this way.
The HashMap provides no guarantee as to the order of the items stored. It may even be in order in some cases. Taken from the javadoc:
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
So it's working as intended. If you're curious as to why this particular example is placed in order, you could check out the source code itself.
Its not just restricted to keys of Integers you may obtain the same with Strings at times.
It just so happens to be at times and you would find numerous instances of the same.
As suggested by others HashMap never guarantees the insertion order while fetching.Since the official doc says to not rely you might find occasions when it would not retain the order so better code likewise.
See this for more
I want to maintain a list of objects such that each object in the list is unique.Also I want to retrieve it at one point. Objects are in thousands and I can't modify their source to add a unique id. Also hascodes are unreliable.
My approach was to utilize the key uniqueness of a map.
Say a maintain a map like :
HashMap<Object,int> uniqueObjectMap.
I will add object to map with as a key and set a random int as value. But how does java determine if the object is unique when used as a key ?
Say,
List listOne;
List listTwo;
Object o = new Object;
listOne.add(o);
listTwo.add(o);
uniqueObjectMap.put(listOne.get(0),randomInt()); // -- > line 1
uniqueObjectMap.put(listTw0.get(0),randomInt()); // --> line 2
Will line 2 give an unique key violation error since both are referring to the same object o ?
Edit
So if will unqiueObjectMap.containsKey(listTwo.get(0)) return true ? How are objects determined to be equal here ? Is a field by field comparison done ? Can I rely on this to make sure only one copy of ANY type of object is maintained in the map as key ?
Will line 2 give an unique key violation error since both are referring to the same object o ?
- No. If a key is found to be already present, then its value will be overwritten with the new one.
Next, HashMap has a separate hash() method which Applies a supplemental hash function to a given hashCode (of key objects), which defends against poor quality hash functions.
It does so by calling the Object's hashcode() function.
The default implementation is roughly equivalent to the object's unique identifier (much like a memory address); however, there are objects that are compare-by-value. If dealing with a compare-by-value object, hashcode() will be overridden to compute a number based on the values, such that two identical values yield the same hashcode() number.
As for the collection items that are hash based, the put(...) operation is fine with putting something over the original location. In short, if two objects yeild the same hashcode() and a positive equals(...) result, then operations will assume that they are for all practical purposes the same object. Thus, put may replace the old with the new, or do nothing, as the object is considered the same.
It may not store two copies in the same "place" as it makes no sense to store two copies at the same location. Thus, sets will only contain one copy, as will map keys; however, lists will possibly contain two copies, depending on how you added the second copy.
How are objects determined to be equal here ?
By using equals and Hashcode function of Object class.
Is a field by field comparison done ?
No, if you dont implement equals and hashcode, java will compare the references of your objects.
Can I rely on this to make sure only one copy of ANY type of object is maintained in the map as key ?
No.
Using a Set is a better approch than using Map because it removes duplicates by his own, but in this case it wont work either because Set determinates duplicates the same way like a Map does it with Keys.
If you will refer to same then it ll not throw an error because when HashMap get same key then it's related value will be overwrite.
If the same key is exist in HashMap then it will be overwritten.
if you want to check if the key or value is already exist or not then you can use:
containsKey() and containsValue().
ex :
hashMap.containsKey(0);
this will return true if the key named 0 is already exist otherwise false.
By getting hashcode value using hash(key.hashCode())
HashMap has an inner class Entry with attributes
final K key;
V value;
Entry<K ,V> next;
final int hash;
Hash value is used to calculate the index in the array for storing Entry object, there might be the scenario where 2 unequal object can have same equal hash value.
Entry objects are stored in linked list form, in case of collision, all entry object with same hash value are stored in same Linkedlist but equal method will test for true equality. In this way, HashMap ensure the uniqueness of keys.
I know this has been asked many times, but I can't find an exact answer to my question.
In chapter 3 of Effective Java, there is a scenario there that shows and explains why hashcode should be overriden together with the equals method. I get the most part of it but there is a part there that I can't understand.
There is a given class there that override the equals method but not the hashCode method. The object is put as a key in a map
Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();
m.put(new PhoneNumber(707, 867, 5309), "Jenny");
I understand that if we get using another equal object (m.get(new PhoneNumber(707, 867, 5309))), it will return null simply because their hashcodes are not overriden to return equal value for equal objects (because it will search for the object in another bucket because of different hashcode).
But according to my understanding, in that situation, there is no guarantee that the hashcodes of the two objects will always return distinct. What if they happen to return the same hashcode?
I think it is explained in this part
Even if the two instances happen to hash to the same bucket, the get
method will almost certainly return null, as HashMap has an
optimization that caches the hash code associated with each entry and
doesn’t bother checking for object equality if the hash codes don’t
match.
I just don't get the cache thing. Can someone explain this elaborately?
Also, I already did my home work, and found a related question
Influence of HashMap optimization that caches the hash code associated with each entry to its get method
But I'm not that satisfied with the answer accepted, also, the answerer says in the comment that
A hash code can be an arbitrary int, thus each hash code can't have
its own bucket. Consequently, some objects with different hash codes
end up in the same bucket.
Which I completely disagree. To my understanding different hashcodes will never end up in the same bucket.
Take a look at how java.util.HashMap calculates a bucket number for a key by hashCode:
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
If hashtable length = 16 then both 128 and 256 will get in bucket #0. Hashtable is an array of entries:
Entry<K,V>[] table
...
class Entry<K,V> {
K key;
V value;
Entry<K,V> next;
int hash;
...
Entries may form a chain (LinkedList). If bucket #0 (table[0]) is empty (null) then the new entry will be placed directly there, otherwise HashMap will find the last entry in the chain and set the last entry's next = new entry.
When this is said "Even if the two instances happen to hash to the same bucket" it doesn't mean that they have same hashcode. Even different hashcodes can map to same bucket [read about hashing].
So even if the keys hash to the same bucket, .equals may not be invoked (due to the caching optimizations) for the relevant element (since not even the hash-codes matches). Thus, even if the relevant element resides in the same bucket, it may never be compared through .equals, and thus not "found".
I have been trying to understand the internal implementation of java.util.HashMap and java.util.HashSet.
Following are the doubts popping in my mind for a while:
Whats is the importance of the #Override public int hashcode() in a HashMap/HashSet? Where is this hash code used internally?
I have generally seen the key of the HashMap be a String like myMap<String,Object>. Can I map the values against someObject (instead of String) like myMap<someObject, Object>? What all contracts do I need to obey for this happen successfully?
Thanks in advance !
EDIT:
Are we saying that the hash code of the key (check!) is the actual thing against which the value is mapped in the hash table? And when we do myMap.get(someKey); java is internally calling someKey.hashCode() to get the number in the Hash table to be looked for the resulting value?
Answer: Yes.
EDIT 2:
In a java.util.HashSet, from where is the key generated for the Hash table? Is it from the object that we are adding eg. mySet.add(myObject); then myObject.hashCode() is going to decide where this is placed in the hash table? (as we don't give keys in a HashSet).
Answer: The object added becomes the key. The value is dummy!
The answer to question 2 is easy - yes you can use any Object you like. Maps that have String type keys are widely used because they are typical data structures for naming services. But in general, you can map any two types like Map<Car,Vendor> or Map<Student,Course>.
For the hashcode() method it's like answered before - whenever you override equals(), then you have to override hashcode() to obey the contract. On the other hand, if you're happy with the standard implementation of equals(), then you shouldn't touch hashcode() (because that could break the contract and result in identical hashcodes for unequal objects).
Practical sidenote: eclipse (and probably other IDEs as well) can auto generate a pair of equals() and hashcode() implementation for your class, just based on the class members.
Edit
For your additional question: yes, exactly. Look at the source code for HashMap.get(Object key); it calls key.hashcode to calculate the position (bin) in the internal hashtable and returns the value at that position (if there is one).
But be careful with 'handmade' hashcode/equals methods - if you use an object as a key, make sure that the hashcode doesn't change afterwards, otherwise you won't find the mapped values anymore. In other words, the fields you use to calculate equals and hashcode should be final (or 'unchangeable' after creation of the object).
Assume, we have a contact with String name and String phonenumber and we use both fields to calculate equals() and hashcode(). Now we create "John Doe" with his mobile phone number and map him to his favorite Donut shop. hashcode() is used to calculate the index (bin) in the hash table and that's where the donut shop is stored.
Now we learn that he has a new phone number and we change the phone number field of the John Doe object. This results in a new hashcode. And this hashcode resolves to a new hash table index - which usually isn't the position where John Does' favorite Donut shop was stored.
The problem is clear: In this case we wanted to map "John Doe" to the Donut shop, and not "John Doe with a specific phone number". So, we have to be careful with autogenerated equals/hashcode to make sure they're what we really want, because they might use unwanted fields, introducing trouble with HashMaps and HashSets.
Edit 2
If you add an object to a HashSet, the Object is the key for the internal hash table, the value is set but unused (just a static instance of Object). Here's the implementation from the openjdk 6 (b17):
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
Hashing containers like HashMap and HashSet provide fast access to elements stored in them by splitting their contents into "buckets".
For example the list of numbers: 1, 2, 3, 4, 5, 6, 7, 8 stored in a List would look (conceptually) in memory something like: [1, 2, 3, 4, 5, 6, 7, 8].
Storing the same set of numbers in a Set would look more like this: [1, 2] [3, 4] [5, 6] [7, 8]. In this example the list has been split into 4 buckets.
Now imagine you want to find the value 6 out of both the List and the Set. With a list you would have to start at the beginning of the list and check each value until you get to 6, this will take 6 steps. With a set you find the correct bucket, the check each of the items in that bucket (only 2 in our example) making this a 3 step process. The value of this approach increases dramatically the more data you have.
But wait how did we know which bucket to look in? That is where the hashCode method comes in. To determine the bucket in which to look for an item Java hashing containers call hashCode then apply some function to the result. This function tries to balance the numbers of buckets and the number of items for the fastest lookup possible.
During lookup once the correct bucket has been found each item in that bucket is compared one at a time as in a list. That is why when you override hashCode you must also override equals. So if an object of any type has both an equals and a hashCode method it can be used as a key in a Map or an entry in a Set. There is a contract that must be followed to implement these methods correctly the canonical text on this is from Josh Bloch's great book Effective Java: Item 8: Always override hashCode when you override equals
Whats is the importance of the #Override public int hashcode() in a HashMap/HashSet?
This allows the instance of the map to produce a useful hash code depending on the content of the map. Two maps with the same content will produce the same hash code. If the content is different, the hash code will be different.
Where is this hash code used internally?
Never. This code only exists so you can use a map as a key in another map.
Can I map the values against someObject (instead of String) like myMap<someObject, Object>?
Yes but someObject must be a class, not an object (your name suggests that you want to pass in object; it should be SomeObject to make it clear you're referring to the type).
What all contracts do I need to obey for this happen successfully?
The class must implement hashCode() and equals().
[EDIT]
Are we saying that the hash code of the key (check!) is the actual thing against which the value is mapped in the hash table?
Yes.
Yes. You can use any object as the key in a HashMap. In order to do so following are the steps you have to follow.
Override equals.
Override hashCode.
The contracts for both the methods are very clearly mentioned in documentation of java.lang.Object. http://java.sun.com/javase/6/docs/api/java/lang/Object.html
And yes hashCode() method is used internally by HashMap and hence returning proper value is important for performance.
Here is the hashCode() method from HashMap
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
It is clear from the above code that hashCode of each key is not just used for hashCode() of the map, but also for finding the bucket to place the key,value pair. That is why hashCode() is related to performance of the HashMap
Any Object in Java must have a hashCode() method; HashMap and HashSet are no execeptions. This hash code is used if you insert the hash map/set into another hash map/set.
Any class type can be used as the key in a HashMap/HashSet. This requires that the hashCode() method returns equal values for equal objects, and that the equals() method is implemented according to contract (reflexive, transitive, symmetric). The default implementations from Object already obey these contracts, but you may want to override them if you want value equality instead of reference equality.
There is a intricate relationship between equals(), hashcode() and hash tables in general in Java (and .NET too, for that matter). To quote from the documentation:
public int hashCode()
Returns a hash code value for the object. This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable.
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language.)
The line
#Overrides public int hashCode()
just tells that the hashCode() method is overridden. This ia usually a sign that it's safe to use the type as key in a HashMap.
And yes, you can aesily use any object which obeys the contract for equals() and hashCode() in a HashMap as key.
In answer to question 2, though you can have any class that can be used to as the key in Hashmap, the best practice is to use immutable classes as keys for the HashMap. Or at the least if your "hashCode", and "equals" implementation are dependent on some of the attributes of your class then you should take care that you don't provide methods to alter these attributes.
Aaron Digulla is absolutely correct. An interesting additional note that people don't seem to realise is that the key object's hashCode() method is not used verbatim. It is, in fact, rehashed by the HashMap i.e. it calls hash(someKey.hashCode)), where hash() is an internal hashing method.
To see this, have a look at the source: http://kickjava.com/src/java/util/HashMap.java.htm
The reason for this is that some people implement hashCode() poorly and the hash() function gives a better hash distribution. It's basically done for performance reasons.
HashCode method for collection classes like HashSet, HashTable, HashMap etc – Hash code returns integer number for the object that is being supported for the purpose of hashing. It is implemented by converting internal address of the object into an integer. Hash code method should be overridden in every class that overrides equals method.
Three general contact for HashCode method
For two equal objects acc. to equal method, then calling HashCode for both object it should produce same integer value.
If it is being called several times for a single object, then it should return constant integer value.
For two unequal objects acc. to equal method, then calling HashCode method for both object, it is not mandatory that it should produce distinct value.