HashMap in Java uses an internal array structure called buckets to store key-value pairs efficiently. Each bucket can contain multiple entries using linked lists to handle hash collisions. The array uses a hash function to determine which bucket should store each key-value pair.
The put operation in HashMap follows a systematic process. First, it calculates the hash code of the key using the hashCode method. Then it determines the bucket index by applying a modulo operation or bitwise AND. If the bucket is empty, it directly inserts the new entry. If there's a collision, it chains the entry to the existing linked list in that bucket.
The get operation retrieves values by first calculating the hash code of the search key to find the correct bucket. It then traverses the linked list or tree in that bucket, comparing each key using the equals method until it finds a match. If found, it returns the corresponding value, otherwise it returns null. This process typically runs in constant time but can degrade to linear time in worst-case scenarios with many collisions.
HashMap handles collisions using separate chaining with linked lists. When a bucket accumulates too many entries, Java 8 and later versions convert the linked list to a Red-Black tree for better performance. The HashMap also automatically resizes when the load factor exceeds 0.75, doubling the array size and rehashing all existing entries to maintain efficient distribution and performance.