The hashCode() method in Java is implemented in the Object class.
Basically, the hashCode() method provides a numeric representation of an object.
hashCode method in the String class uses the following formula.
s.charAt(0) * 31^(n-1) + s.charAt(1) * 31(n-2) + ... + s.charAt(n-1)
HashMap
The Map interface in Java is not an extension of the Collection interface. It starts off its own interface hierarchy.
The interface describes a mapping from keys to values, without duplicate keys, by definition.
As a result, maps provide a good way of searching for an object on the value of another.
Other than the fact that it is key and value mapping implementation. HashMap is a hashtable as we discussed so far.
Here are some code snippets from HashMap class (Java 7).
// The table, resized as necessary. Length MUST Always be a power of two.
Entry<K, V>[] table;
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY];
init();
}
static class Entry<K, V> ... {
final K key;
V value;
Entry<K, V> next;
int hash;
Entry(int h, K k, V v, Entry<K, V> n) {
value = v;
next = n;
key = k;
hash = h;
}
}
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;
}
static int indexFor(int h, int length) {
return h & (length - 1);
}
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K, V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
Major methods of the HashMap in java are:
put(key, value): associates the value with the key in the map.
get(key): returns the value of the key or null.
keySet(): returns a set view of the keys in the map.
values(): returns a collection view of the values in the map.
For keySet() and values() methods, we can use an Iterator to traverse the returned values.
A simple application: implementing the frequency count of words
// you can try to tune initial capacity and load factor.
// default values are 16 and 0.75 respectively.
Map<String, Integer> freqOfWords = new HashMap<String, Integer>(16, 0.65f);
String[] words = "coming together is a beginning keeping together is progress working together is success".split(" ");
for (String word : words) {
Integer frequency = freqOfWords.get(word);
if (frequency == null) {
frequency = 1;
} else {
frequency++;
}
freqOfWords.put(word, frequency);
}
Iterate all of the words and print each per one line
Iterator<String> itr = freqOfWords.keySet().iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
Or
for (String word : freqOfWords.keySet()) {
System.out.println(word);
}
HashSet
Java provides HashSet class which is a regular set in which all objects are distinct.
HashSet's major methods are:
add(key): adds a key to the set.
contains(key): return true if the set has that key.
iterator(): return an iterator over the elements.
HashSet class implements the Set interface using HashMap instance.
public class HashSet<E> implements Set<E> {
private ... HashMap<E, Object> map;
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT) == null;
}
}
It creates HashMap instance and it uses HashMap's put method to add a new element but with dummy object as its value.
And, it adds, or puts, a new element only if it is not already present in the map.
It stores and retrieves elements by using a hash function that converts elements into an integer.