Android advanced interview questions detailed explanation of hashmap put () underlying principle and ArrayList how to ensure thread safety

text

insert image description here

Please talk about the underlying principle of hashmap put(). When a conflict occurs, how to add it (traverse along the linked list, and compare the key values ​​one by one to see if they are consistent. If they are consistent, overwrite and replace them. After the inconsistent traversal, insert the position)?

What is this question trying to investigate?

1. What is the basic principle of the put function of Hashmap?

Knowledge points of inspection

The underlying source code of HashMap

How Candidates Answer
Analysis of the underlying source code of the HashMap put function
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
    
    
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0) //首次放入元素时,分配table空间-默认size=16
            n = (tab = resize()).length;
 
        if ((p = tab[i = (n - 1) & hash]) == null) // 算出新node在table中的位置,若对应位置为null,新建一个node并放入对应位置.
        // 注意:  (n - 1) & hash 求余操作 等价于 hash%n 
            tab[i] = newNode(hash, key, value, null);
        else {
    
                                          //在table对应位置有node时
            Node<K,V> e; K k;
            if (p.hash == hash &&                   // key一样 (hash值相同,且key 一样,相同实例或者满足Object.equals方法)
                ((k = p.key) == key || (key != null && key.equals(k)))) // 不满足此条件则发生hash碰撞
                e = p;
            else if (p instanceof TreeNode)                // hash碰撞的情况下,用链表解决,链表大于8时,改为红黑树. 当node为treeNode时,putTreeVal->红黑树
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
    
                                                                                   //hash
                for (int binCount = 0; ; ++binCount) {
    
                              //用for循环将链表指针后移,将新node在链表加在尾部
                    if ((e = p.next) == null) {
    
    
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // 当链表长度大于8时,转成红黑树
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&                                               
                        ((k = e.key) == key || (key != null && key.equals(k))))         
                        break;                                                          
                    p = e;
                }
            }
            if (e != null) {
    
     // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)  //当node中旧的值null或者onlyIfAbsent==false时,将新的value替换原来的value.
                    e.value = value;
                afterNodeAccess(e); //新node塞入table后做的做的事情,在HashMap中是一个空方法(LinkedHashMap中有有使用, move node to last)
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)  //新的size大于阈值(默认0.75*table.length)时,扩容.
            resize();
        afterNodeInsertion(evict);
        return null;
    }

The idea is as follows:

  • Calculate the array subscript index after hashing the hashCode() of the key;
  • If the current array table is null, perform resize() initialization;
  • If there is no collision, put it directly into the bucket corresponding to the subscript;
  • If there is a collision and the node already exists, replace the value;
  • If it is found to be a tree structure after the collision, mount it on the tree.
  • If it is a linked list after the collision, add it to the end of the linked list, and judge that if the linked list is too long (greater than or equal to TREEIFY_THRESHOLD, default 8), convert the linked list into a tree structure;
  • After the data is put, if the amount of data exceeds the threshold, it must be resized.

Through the above ideas, we can see that when the put function of HashMap is added, it will judge whether it is a linked list after the collision. If it is a linked list, it will be added to the end of the linked list, and if the linked list is too long (greater than or equal to TREEIFY_THRESHOLD, default 8), then Convert the linked list into a tree structure.

Please tell me how ArrayList ensures thread safety, except for adding keywords?

What is this question trying to investigate?

1. The underlying principle of ArrayList?

Knowledge points of inspection

Understanding of the underlying source code of ArrayList

how do you answer
How ArrayList guarantees thread safety
  • Inherit Arraylist, and then rewrite or write your own methods according to requirements. These methods should be written as synchronized, and the methods of ArrayList are called in these synchronized methods.
  • You can use the Collections.synchronizedList() function as follows
List<Map<String,Object>> data=new ArrayList<Map<String,Object>>();
List<Map<String,Object>> data=Collections.synchronizedList(new ArrayList<Map<String,Object>>());

insert image description here

  • Use CopyOnWriteArrayList
List<String> k=new CopyOnWriteArrayList<>();

End of article

More Android interview questions can be scanned for free!

↓↓↓【Preview】↓↓↓

img

Guess you like

Origin blog.csdn.net/Android_XG/article/details/130862418