For Dachang Offer! These HashMap knowledge points frequently asked in Java interviews, you must know

Preface

HashMap should be regarded as a must-question for Java programmer interviews, because there are too many knowledge points, it is very suitable for investigating the Java foundation of the interviewer. Today I have compiled a HashMap interview question frequently asked by major manufacturers to share with you, hope Can I give you a little help.
Insert picture description here

1. The realization principle of HashMap?

This question can be composed of the following serial guns to ask

Have you read the source code of HashMap and know the principle?

Why use array + linked list?

What solutions do you know about hash conflicts?

Can I use LinkedList instead of array structure?

Since it is possible, why does HashMap use an array instead of LinkedList?

1. Have you read the source code of HashMap and know the principle?

To solve this problem, um, of course, you must read the HashMap source code. As for the principle, the picture below is very clear:
Insert picture description here

HashMap uses Entry arrays to store key-value pairs. Each key-value pair forms an Entry entity. The Entry class is actually a one-way linked list structure, which has a Next pointer and can connect to the next Entry entity.

Only in JDK1.8, when the length of the linked list is greater than 8, the linked list will be converted into a red-black tree!

2. Why use array + linked list?

The array is used to determine the position of the bucket, which is obtained by modulating the length of the array by the hash value of the key of the element.

The linked list is used to solve the problem of hash conflict. When the hash value is the same, a linked list is formed at the corresponding position on the array. ps: The hash value here does not refer to the hashcode, but the XOR of the high and low 16 bits of the hashcode. As for why you want to do this, continue to look down.

3. What solutions do you know about hash conflicts?

There are four well-known (1) open addressing method (2) chain address method (3) rehashing method (4) public overflow area method

ps: If you are interested in expanding, you will understand by searching it yourself, and this will not expand!

4. Can I use LinkedList instead of array structure?

Let me explain a little bit here. The meaning of this question is that the source code is like this

Entry[] table = new Entry[capacity];

ps: Entry is a linked list node.

Then I use the following

List table = new LinkedList();

Is it feasible?

The answer is obvious, it must be possible.

5.Since it is possible, why does HashMap use an array instead of LinkedList?

Because using arrays is the most efficient!

In HashMap, the location of the locating bucket is obtained by modulo the length of the array using the hash value of the key of the element. At this point, we have got the location of the bucket. Obviously, the search efficiency of the array is greater than that of the LinkedList.

Then ArrayList, the bottom layer is also an array, and the search is also fast, why not use ArrayList?

(When Brother Yan wrote here, he couldn't help but feel that he really had an idea, and he asked himself to death. Fortunately, I came up with the answer after a thought)

Because the basic array structure is used, the expansion mechanism can be defined by yourself. The expansion of the array in the HashMap is just a power of 2, and the efficiency of the modulo operation is high.

The expansion mechanism of ArrayList is 1.5 times expansion, so why ArrayList is 1.5 times expansion is not explained in this article.

2. Under what conditions does HashMap expand?

This question can be composed of the following serial guns to ask

Under what conditions does HashMap expand?

Why is the expansion to the power of 2?

Why do we need to XOR the high 16 bits first and then take the modulo operation?

1.Under what conditions does HashMap expand?

If the bucket is full (over load factor*current capacity), it must be resized.

The load factor is 0.75, in order to avoid hash collision to the greatest extent

current capacity is the current array size.

2. Why is the expansion a power of 2?

In order to store and store efficiently, HashMap should have as few collisions as possible. It is to distribute the data as evenly as possible. The length of each linked list is roughly the same. This implementation is based on the algorithm of which linked list is stored in the data; this algorithm is actually modulo, hash% length.

However, everyone knows that this kind of operation is not as fast as the shift operation.

Therefore, hash&(length-1) is optimized in the source code.

That is to say hash%length==hash&(length-1)

So why is it 2 to the nth power?

Because the n-th power of 2 is actually n zeros behind 1, and the n-th power of 2 -1 is actually n 1s.

For example, when the length is 8, 3&(8-1)=3 2&(8-1)=2, different positions will not collide.

When the length is 5, 3&(5-1)=0 2&(5-1)=0, both are on 0, and there is a collision.

Therefore, the guarantee that the volume is 2 to the power of n is to ensure that when doing (length-1), every bit can be &1, that is, and 1111...1111111 are ANDed.

3.Why do you need to XOR the high 16 bits first and then take the modulo operation?

Let me show you the hash method in jdk1.8. 1.7 is more complicated, so let's ignore it.
Insert picture description here
Hashmap does this just to reduce the chance of hash collision.

For example, when our length is 16, the hash code (the hash code corresponding to the key of the string "abcabcabcabcabc") pairs (16-1) and the operation, for the hashCode generated by multiple keys, just hash The last 4 bits of the code are 0, no matter how the high bits change, the final result is 0.

As shown in the figure below
Insert picture description here
, after adding the "disturbance function" with the upper 16 bits XOR and the lower 16 bits, the result
Insert picture description here
can be seen as follows : Before the disturbance function is optimized: 1954974080% 16 = 1954974080 & (16-1) = 0 After the disturbance function is optimized :1955003654% 16 = 1955003654 & (16-1) = 6 Obviously, it reduces the chance of collision.

3. Tell me about the get/put process of hashmap?

This question can be composed of the following serial guns to ask

Do you know the process of put elements in hashmap?

Do you know the process of getting elements in hashmap?

What hash algorithms do you still know?

Talk about the implementation of hashcode in String? (This question has been asked by many big companies)

1. Know what the process of put elements in hashmap is like?

Perform a hash operation on the hashCode() of the key and calculate the index;

If there is no collision, put it directly into the bucket;

If there is a collision, after the buckets exist in the form of a linked list;

If the collision causes the linked list to be too long (greater than or equal to TREEIFY_THRESHOLD), convert the linked list to a red-black tree (changes in JDK1.8);

If the node already exists, replace the old value (to ensure the uniqueness of the key)

If the bucket is full (over load factor*current capacity), it must be resized.

2. Do you know what is the process of getting elements in hashmap?

Perform a hash operation on the hashCode() of the key and calculate the index;

If it hits directly in the first node in the bucket, it will return directly;

If there is a conflict, use key.equals(k) to find the corresponding Entry;

If it is a tree, search through key.equals(k) in the tree, O(logn);

If it is a linked list, search through key.equals(k) in the linked list, O(n).

3. What hash algorithms do you still know?

Let me talk about the hash algorithm first. The hash function refers to mapping a large range to a small range. The purpose of mapping a large area to a small area is often to save space and make data easy to save.

The more famous ones are MurmurHash, MD4, MD5, etc.

4. Talk about the implementation of hashcode in String? (This question is very frequent)

public int hashCode() {

int h = hash;

if (h == 0 && value.length > 0) {

    char val[] = value;

    for (int i = 0; i < value.length; i++) {

        h = 31 * h + val[i];

    }

    hash = h;

}

return h;

}

The hashCode calculation method in the String class is relatively simple, that is, using 31 as the weight, each bit is the ASCII value of the character, and the natural overflow is used to equivalently take the modulus.

The hash calculation formula can be counted as s[0]31^(n-1) + s[1]31^(n-2) +… + s[n-1]

Then why is 31 the prime number?

Mainly because 31 is an odd prime number, so 31 i=32 i-i=(i<<5)-i, this kind of calculation combined with displacement and subtraction is much faster than general calculations.

4. Why is the hashmap changed to a red-black tree when the number of linked list elements exceeds 8?

This question can be composed of the following serial guns to ask

Do you know what has been changed in hashmap in jdk1.8?

Why not directly use red-black trees when resolving hash conflicts? Instead, choose to use linked lists first, then red-black trees?

I don’t need a red-black tree, can I use a binary search tree?

So why is the threshold 8?

When the linked list turns into a red-black tree, when will it degenerate into a linked list?

1. Do you know what is changed in hashmap in jdk1.8?

The array + list structure to an array of linked lists + + red-black tree.

Optimized the hash algorithm for high-order operations: h^(h>>>16)

After expansion, the elements are either in the original position or moved to the power of 2 in the original position, and the order of the linked list remains unchanged.

The last one is the key point. Because of the change in the last one, the hashmap in 1.8 will not cause an endless loop problem.

2. Why not directly use the red-black tree when solving the hash conflict? Instead, choose to use the linked list first, and then switch to the red-black tree?

Because red-black trees need to perform left-handed, right-handed, and color-changing operations to maintain balance, singly linked lists do not.

When the number of elements is less than 8, when the query operation is performed at this time, the linked list structure can already guarantee the query performance. When there are more than 8 elements, a red-black tree is needed to speed up the query, but the efficiency of adding new nodes slows down.

Therefore, if the red-black tree structure is used at the beginning, there are too few elements, and the new efficiency is relatively slow, which is undoubtedly a waste of performance.

3. I don't need a red-black tree, can I use a binary search tree?

can. But the binary search tree will become a linear structure under special circumstances (this is the same as the original linked list structure, which causes deep problems), and the traversal search will be very slow.

4. Then why the threshold is 8?

I don't know, wait for the jdk author to answer.

The answers to this question are all nonsense.

I just posted an answer from Niuke.com, as shown in the figure below.
Insert picture description here
Did you see the bug? The intersection is 6.64? The intersection is clearly 4, okay.

log4 = 2,4 / 2 = 2。

The author of jdk chose 8 and must have gone through strict calculations. When the length is 8, instead of ensuring the search cost of the linked list structure, it is better to convert to a red-black tree and maintain its balanced cost instead.

5. When the linked list is converted to a red-black tree, when will it degenerate into a linked list?

When it is 6, it is converted to a linked list. There is a difference of 7 in the middle to prevent frequent conversion between the linked list and the tree. Suppose, if the number of linked lists is designed to exceed 8, the linked list is converted into a tree structure, and the number of linked lists is less than 8, the tree structure is converted into a linked list. If a HashMap keeps inserting and deleting elements, the number of linked lists is hovering around 8, then Tree to linked list and linked list to tree will happen frequently, and the efficiency will be very low.

Five, the concurrency problem of HashMap?

This question can be composed of the following serial guns to ask

What are the problems with HashMap in a concurrent programming environment?

Are there still these problems in jdk1.8?

How do you generally solve these problems?

What are the problems with HashMap in a concurrent programming environment?

(1) Multi-threaded expansion, causing endless loop problems

(2) Elements may be lost when multi-threaded put

(3) After putting a non-null element, the get out is null

Are there still these problems in jdk1.8?

In jdk1.8, the infinite loop problem has been solved. The other two problems still exist.

How do you generally solve these problems?

Such as ConcurrentHashmap, Hashtable and other thread-safe collection classes.

6. What do you generally use as the key of HashMap?

This question can be composed of the following serial guns to ask

Can a key be a null value?

What do you generally use as the key of HashMap?

What's wrong with using a variable class as the key of HashMap?

How can you implement a custom class as the key of HashMap?

1.Can the key be a Null value?

It must be possible. When the key is null, the final value of the hash algorithm is calculated as 0, which is placed in the first position of the array.
Insert picture description here

2. What do you generally use as the key of HashMap?

Generally, immutable classes such as Integer and String are used as HashMap as the key, and String is the most commonly used.

(1) Because the string is immutable, the hashcode is cached when it is created and does not need to be recalculated. This makes the string very suitable as a key in the Map, and the processing speed of the string is faster than other key objects. This is that the keys in HashMap often use strings.

(2) Because equals() and hashCode() methods are used when obtaining objects, it is very important for the key object to rewrite these two methods correctly. These classes have already overwritten hashCode() and equals very standardized ()method.

3. What is the problem when I use a variable class as the key of HashMap?

The hashcode may change, causing the put value to be unable to get out, as shown below

HashMap<List, Object> changeMap = new HashMap<>();

List list = new ArrayList<>();

list.add(“hello”);

Object objectValue = new Object();

changeMap.put(list, objectValue);

System.out.println(changeMap.get(list));

list.add("hello world");//hashcode has changed

System.out.println(changeMap.get(list));

The output value is as follows

java.lang.Object@74a14482

null

4. How to implement a custom class as the key of HashMap?

This question examines two knowledge points

What should I pay attention to when rewriting hashcode and equals methods?

How to design an immutable class

For question 1, remember the following four principles

(1) If two objects are equal, hashcode must be equal

(2) The two objects are not equal, the hashcode is not necessarily different

(3) The hashcode is equal, the two objects are not necessarily equal

(4) The hashcode is not equal, the two objects must be different

For problem two, remember how to write an immutable class

(1) Add a final modifier to the class to ensure that the class is not inherited.

If the class can be inherited, it will destroy the immutability mechanism of the class. As long as the inherited class overrides the methods of the parent class and the inherited class can change the value of member variables, once the child class appears in the form of the parent class, there is no guarantee that the current class is mutable.

(2) Ensure that all member variables must be private, and add final modification

In this way, the member variables are guaranteed to be unchangeable. But only doing this step is not enough, because if it is an object member variable, it may change its value externally. So the fourth point makes up for this shortcoming.

(3) Does not provide methods to change member variables, including setters

Avoid changing the value of member variables through other interfaces and destroying immutable characteristics.

(4) All members are initialized through the constructor, deep copy (deep copy)

If the object passed by the constructor is directly assigned to the member variable, the value of the internal variable can be changed by modifying the passed object. E.g:

public final class ImmutableDemo {  

private final int[] myArray;  

public ImmutableDemo(int[] array) {  

    this.myArray = array; // wrong  

}  
}

This method cannot guarantee immutability. MyArray and array point to the same memory address. Users can change the value of myArray by modifying the value of the array object outside of ImmutableDemo.

In order to ensure that the internal value is not modified, deep copy can be used to create a new memory to save the incoming value. Correct way:

public final class MyImmutableDemo {  

private final int[] myArray;  

public MyImmutableDemo(int[] array) {  

    this.myArray = array.clone();   

}   
}

(5) In the getter method, do not directly return the object itself, but clone the object and return a copy of the object

This approach is also to prevent the object from leaking out, and prevent the member variable from being directly manipulated after the internal variable member object is obtained through the getter, which causes the member variable to change.

to sum up

October is about to pass. Those who are still looking for work should hurry up.
The editor has sorted out most of the interview questions and answers involved in the interview with Dachang java programmers to share with you for free, hoping to help you, friends in need can see the free way to receive them below !

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Get
information here: password CSDN

Insert picture description here
Insert picture description here

To get the information, click here: CSDN
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

Finally, thank you for your support, and hope that the information compiled by the editor can help you! I also wish everyone a promotion and salary increase!
Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_47955802/article/details/109230471