HashMap vs Hashtable
Key Differences
- Thread Safety: Hashtable is synchronized, while HashMap is not
- Null Values: HashMap allows one null key and multiple null values; Hashtable prohibits null keys and values
- Performance: HashMap generally performs better in single-threaded environments due to lack of synchronization overhead
HashMap Fundamentals
HashMap is a widely used collection class in Java that implements the Map interface. It extends AbstractMap and implements the Map, Cloneable, and Serializable interfaces.Class Hierarchy
java.lang.Object java.util.AbstractMapType Parameters: - K - the type of keys maintained by this map - V - the type of mapped values All Implemented Interfaces: - Serializable, Cloneable, Mapjava.util.HashMap
Primitive Types and Wrapper Classes
| Primitive Type | Reference Type |
|---|---|
| boolean | Boolean |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
Common Operations
Creating a HashMap
import java.util.HashMap; HashMap<Integer, String> fruitMap = new HashMap<Integer, String>();
Adding Elements
The put() method uses hashCode() to determine the bucket position for storing key-value pairs.
public class HashMapDemo {
public static void main(String[] args) {
HashMap<Integer, String> fruitMap = new HashMap<Integer, String>();
fruitMap.put(1, "Apple");
fruitMap.put(2, "Banana");
System.out.println(fruitMap);
}
}
Accessing Elements
The get(key) method retrieves values using the key's hashCode to locate the appropriate bucket.
public class HashMapAccess {
public static void main(String[] args) {
HashMap<Integer, String> fruitMap = new HashMap<Integer, String>();
fruitMap.put(1, "Apple");
fruitMap.put(2, "Banana");
System.out.println(fruitMap.get(1));
}
}
Removing Elements
public class HashMapRemove {
public static void main(String[] args) {
HashMap<Integer, String> fruitMap = new HashMap<Integer, String>();
fruitMap.put(1, "Apple");
fruitMap.put(2, "Banana");
fruitMap.remove(1);
fruitMap.clear();
}
}
Counting Elements
The size() method returns the number of key-value pairs in the HashMap.
Iterating Through HashMap
// Method 1: Using keySet()
Iterator<String> keyIterator = fruitMap.keySet().iterator();
while (keyIterator.hasNext()) {
String key = keyIterator.next();
System.out.println(key + "=" + fruitMap.get(key));
}
// Method 2: Using entrySet()
Iterator<Map.Entry<String, Integer>> entryIterator = fruitMap.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<String, Integer> entry = entryIterator.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "=" + value);
}
HashMap Constructors and Internal Variables
Constructors
Default Constructor
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
}
Creates an empty HashMap with default initial capacity (16) and load factor (0.75).
Capacity-Specified Constructor
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
Creates an empty HashMap with specified initial capacity and default load factor.
Full Parameter Constructor
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
Creates an empty HashMap with specified capacity and load factor.
Map-Based Constructor
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
Creates a new HashMap with the same mappings as the specified Map.
Internal Variables
- DEFAULT_INITIAL_CAPACITY = 16 (must be a power of two)
- MAXIMUM_CAPACITY = 1 << 30
- DEFAULT_LOAD_FACTOR = 0.75f
- TREEIFY_THRESHOLD = 8 (converts linked list to tree when exceeded)
- UNTREEIFY_THRESHOLD = 6 (converts tree back to list when below this)
- MIN_TREEIFY_CAPACITY = 64 (minimum capacity before tree conversion)
- table - array storing elements (always power of two size)
- entrySet - collection containing map entries
- size - number of key-value pairs
- modCount - counter for structural modifications
- threshold - capacity threshold for resizing
- loadFactor - actual load factor
Key Performance Factors
Initial Capacity and Load Factor
These two factors significantly impact HashMap performance:
- Initial Capacity: The capacity when the HashMap is created
- Load Factor: Determines when the HashMap should be resized (default 0.75)
Collision Handling
HashMap handles collisions through:
- Linked lists for small collision chains
- Red-black trees for longer collision chains (when length exceeds TREEIFY_THRESHOLD)
Internal Data Structure
HashMap uses an array of nodes, where each node can be part of a linked list or a red-black tree depending on collision patterns.
Hashing Algorithm
HashMap uses a combination of key's hashCode() and additional bit manipulation to determine bucket positions, ensuring even distribution of entries.