[Short Video Emotional Communication Number Project, a way to make money in subdivided fields] Java: A step-by-step realization from Map to HashMap!

Insert picture description here
The course is very good, what is needed.
Source of the project: The
world’s way to the extreme, the people’s firewood, rice, oil and salt; the extreme cold and warmth of life, a love word for men and women.
Short video emotional communication number project, a way to make money in subdivided fields [video course]
Project outline:
1. The underlying logic of Douyin Transmitting Number
2. The specific operation of Douyin Transmitting Number
3. Project analysis
4. Summarizing and concluding the
paper, it’s finally shallow. The important thing is to give you an idea, give you a direction, find your shining points, and create your own pipeline income. If you can earn 10 yuan, you can earn it. For 100 yuan, throw yourself away and keep trying and making mistakes to grow quickly. For example, you can immediately create an account on Douyin to spread the word and execute it quickly. If you think about it, do it right away. I wish you all a good year of the Ox in 2021.
Insert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description hereInsert picture description here


1. Map

1.1 Map Interface
In Java, Map provides a key-value mapping relationship. The map cannot contain duplicate keys, and each key can only be mapped to one value.
Based on Map key-value mapping, java.util provides HashMap (most commonly used), TreeMap, Hashtble, LinkedHashMap and other data structures.
The main features of several derived Maps:
HashMap: The most commonly used data structure. The mapping relationship between keys and values ​​is realized through the Hash function. When the key to be traversed is an unordered
TreeMap: a data structure constructed using red-black trees, because of the principle of red-black trees, keys can be sorted naturally, so the keys of TreeMap are traversed in natural order (ascending order) by default Arranged.
LinkedHashMap: Save the order of insertion. The records obtained by traversal are in the order of insertion.
1.2 Hash
Hash (hash function) is to transform an input of any length into a fixed-length output through a hash algorithm. The return value of the Hash function is also called a hash code digest or hash. The function of Hash is shown in the following figure:
Insert picture description here
Hash function can achieve a better balance between time and space by selecting an appropriate function.
Two ways to solve Hash: zipper method and linear detection method

interface Entry<K,V>

Implementation based on linked list in HashMap

static class Node<K,V> implements Map.Entry<K,V> {
    
    
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
    
    
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

Realize in tree way:

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    
    
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
    
    
            super(hash, key, val, next);
        }

1.4 Map Convention API
1.4.1
The addition, deletion and modification of the basic API agreement in Map :

int size();  // 返回大小
boolean isEmpty(); // 是否为空
boolean containsKey(Object key); // 是否包含某个键
boolean containsValue(Object value); // 是否包含某个值
V get(Object key); // 获取某个键对应的值 
V put(K key, V value); // 存入的数据 
V remove(Object key); // 移除某个键
void putAll(Map<? extends K, ? extends V> m); //将将另一个集插入该集合中
void clear();  // 清除
Set<K> keySet(); //获取 Map的所有的键返回为 Set集合
Collection<V> values(); //将所有的值返回为 Collection 集合
Set<Map.Entry<K, V>> entrySet(); // 将键值对映射为 Map.Entry,内部类 Entry 实现了映射关系的实现。并且返回所有键值映射为 Set 集合。 
boolean equals(Object o); 
int hashCode(); // 返回 Hash 值
default boolean replace(K key, V oldValue, V newValue); // 替代操作
default V replace(K key, V value);

1.4.2 Map's more advanced API

default V getOrDefault(Object key, V defaultValue); //当获取失败时,用 defaultValue 替代。

default void forEach(BiConsumer<? super K, ? super V> action)  // 可用 lambda 表达式进行更快捷的遍历

default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function); 

default V putIfAbsent(K key, V value);

default V computeIfAbsent(K key,
            Function<? super K, ? extends V> mappingFunction);

default V computeIfPresent(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction);

default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction)

default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction)   

1.4.3 Use of Map Advanced API
getOrDefault() When the value is obtained by key, and the corresponding key or value does not exist, the default value is returned to avoid the occurrence of null during use and avoid program exceptions.
ForEach() is passed into the BiConsumer functional interface. The meaning is actually the same as Consumer. Both accept have methods, except that BiConsumer has an additional andThen() method, which receives a BiConsumer interface, executes this interface first, and then executes the passed parameters The accept method.

      Map<String, String> map = new HashMap<>();
        map.put("a", "1");
        map.put("b", "2");
        map.put("c", "3");
        map.put("d", "4");
        map.forEach((k, v) -> {
    
    
            System.out.println(k+"-"+v);
        });
    }

1.5 From Map to HashMap
HashMap is an implementation class of Map, and it is also the most commonly used implementation class of Map.
1.5.1 Inheritance of HashMap

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable 

In the implementation of HashMap, the method to resolve Hash conflicts is the zipper method. Therefore, in principle, the realization of HashMap is an array + linked list (the entry of the array to save the linked list). When the linked list is too long, in order to optimize the query rate, HashMap converts the linked list into a red-black tree (the root node of the array storage tree), so that the query rate is log(n) instead of the O(n) of the linked list.

2. HashMap
First, HashMap is participated by two masters, Doug Lea and Josh Bloch. At the same time, Java's Collections collection system and concurrent framework Doug Lea have also made a lot of contributions.
2.1 Basic Principles
For an insert operation, first convert the key to the subscript of the array through the Hash function. If the array is empty, create a node directly and put it into the array. If there are nodes in the array subscript, that is, Hash conflicts, use the zipper method to generate a linked list insertion.
Insert picture description here
If there is a Hash conflict, use the zipper method to insert, we can insert at the head of the linked list, or at the end of the linked list, so the head insertion method is used in JDK 1.7, and the tail insertion is used in subsequent versions of JDK 1.8 law.
JDK 1.7 may use head insertion based on the most commonly used data inserted recently, but one of the problems caused by the head insertion method is that there will be an infinite loop in the replication of multi-threaded linked lists. So the tail insertion method adopted after JDK 1.8.
In HashMap, the definition of the array + linked list mentioned earlier

transient Node<K,V>[] table;
static class Node<K,V> implements Map.Entry<K,V> 
public HashMap() {
    
     // 空参
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
    public HashMap(int initialCapacity) {
    
     //带有初始大小的,一般情况下,我们需要规划好 HashMap 使用的大小,因为对于一次扩容操作,代价是非常的大的
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    public HashMap(int initialCapacity, float loadFactor); // 可以自定义负载因子  public HashMap(int initialCapacity, float loadFactor); // 可以自定义负载因子

The three constructors have not fully initialized the HashMap. When we insert the data for the first time, the heap memory is allocated, which improves the response speed of the code.
2.2 Hash function definition in HashMap

static final int hash(Object key) {
    
    
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); // 将 h 高 16 位和低 16 位 进行异或操作。
    }
// 采用 异或的原因:两个进行位运算,在与或异或中只有异或到的 0 和 1 的概率是相同的,而&和|都会使得结果偏向0或者1。

It can be seen here that the key of the Map can be null, and the hash is a specific value of 0.
The purpose of Hash is to get the subscript of the array table. The goal of the Hash function is to evenly distribute the data in the table.
Let us first look at how to get the corresponding array subscript through the hash value. The first method: hash%table.length(). However, the division operation in the CPU is much slower than addition, subtraction, and multiplication, and it is inefficient. The second method table[(table.length-1) & hash] is an AND operation and a subtraction, which is still faster than division. The constraint here is table.length = 2^N.
table.length =16
table.length -1 = 15 1111 1111
//Any number and operation with it, get the low 8 bits of this number, and the other bits are 0

The above example allows us to get the corresponding subscript, and (h = key.hashCode()) ^ (h >>> 16) allows the high 16 to also participate in the calculation, so that the data can be fully utilized. In general, the index of the table is not It will exceed 216, so we directly discard the high-level information. ^ (h >>> 16) Let us use the high-level information even with a small amount of data. If the index of the table exceeds 216, the high 16 of hashCode() is XORed with 16 zeros and the hash obtained is fair.
2.3 HashMap insertion operation As
we already know above, if the corresponding table subscript is obtained through Hash, we add the corresponding node to the linked list to complete a Map mapping. Indeed, the HashMap implementation in JDK1.7 is like this. Let's take a look at JDK for realizing put operation.
Locate the put() operation.

Guess you like

Origin blog.csdn.net/ncw8080/article/details/113993662