Análisis del código fuente de HashMap ------ HashMap escrito a mano

Mencionamos que en JDK7, la capa inferior de HashMap usaba una matriz más una lista vinculada.
Así que imitemos su capa inferior para escribir. Como mencionamos antes, implementa la interfaz Map. La capa inferior de HashMap usa Node para almacenar pares clave-valor.
Para HashMap en el estado JDK7,
primero usamos la colección de listas para almacenar datos.
Creación de
uso de ArrayListHashMap.java private final ArrayList<Node<K,V>> arrayList = new ArrayList<>();para almacenar múltiples conjuntos de pares clave-valor

package com.hashmap;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author 龙小虬
 * @date 2021/3/25 20:05
 * 缺点:查询速度过慢  有重复数据
 */
public class ArrayListHashMap<K,V>{
    
    

    private final ArrayList<Node<K,V>> arrayList = new ArrayList<>();

    public V get(Object key) {
    
    
        for (Node<K,V> node : arrayList) {
    
    
            // 如果有数据则返回
            if(node.key.equals(key)){
    
    
                return node.value;
            }
        }
        return null;
    }

    public V put(K key, V value) {
    
    
        Node<K,V> node = new Node<K,V>(key,value);
        arrayList.add(node);
        return value;
    }


    static class Node<K,V>{
    
    

        private final K key;

        private final V value;

        public Node(K key, V value) {
    
    
            this.key = key;
            this.value = value;
        }
    }

    public static void main(String[] args) {
    
    
        ArrayListHashMap<Object, Object> arrayListHashMap = new ArrayListHashMap<>();
        arrayListHashMap.put("a","a");
        arrayListHashMap.put(97,97);
        System.out.println(arrayListHashMap.get(97));
    }
}

De esta manera, escribimos los datos del par clave-valor de ArrayList. Pero cuando vemos el método Get (), podemos ver que su complejidad es suficiente para llegar a O (N). Si necesitamos almacenar millones de datos, entonces estamos buscando un dato, el más lento puede ser Todos estos millones de los datos se vuelven a atravesar? ? ?

Finalmente, se agrega la matriz.

Utilice el valor hash de cada dato y guárdelo en una matriz.
Esto se debe a que hay una especificación involucrada en el manual de desarrollo de Java de Ali. Enfatizado

1. 【强制】关于 hashCode 和 equals 的处理,遵循如下规则:
1) 只要覆写 equals,就必须覆写 hashCode。
2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的对象必须覆
写这两个方法。
3) 如果自定义对象作为 Map 的键,那么必须覆写 hashCode 和 equals。
说明:String 已覆写 hashCode 和 equals 方法,所以我们可以愉快地使用 String 对象作为 key 来使用。

Como se menciona en la siguiente descripción, String ha reescrito hashCode y equals. Entonces usaremos String para el tipo de par clave-valor de HashMap que imitamos más adelante.

El primero usa Arraylist porque es similar a una lista vinculada, así que la usamos, y ahora usamos una lista vinculada.

Porque queremos usar matriz + lista vinculada para lograr. Por lo tanto, necesitamos usar una matriz para almacenar la lista vinculada para lograr tal requisito.
Creación de
uso ExtHashMap.java private Node[] objects = new Node[10000];para almacenar la lista.

el código se muestra a continuación

package com.hashmap;

/**
 * @author 龙小虬
 * @date 2021/3/30 20:22
 */
public class ExtHashMap<K, V> {
    
    

    private Node[] objects = new Node[10000];

    static class Node<K, V> {
    
    
        public K k;
        public V v;
        Node<K, V> next;

        public Node(K k, V v) {
    
    
            this.k = k;
            this.v = v;
        }

        public void setV(V v) {
    
    
            this.v = v;
        }
    }

    public void put(K k, V v) {
    
    
        int index = k == null ? 0 : k.hashCode() % objects.length;
        Node<K, V> oldNode = objects[index];
        // 判断是否存在
        if (oldNode == null) {
    
    
            objects[index] = new Node<>(k, v);
        } else {
    
    
            // 发生hash碰撞则存放到链表后面
            for (Node<K, V> oldNodeMap = objects[index]; oldNodeMap != null; oldNodeMap = oldNodeMap.next) {
    
    
                if (oldNodeMap.k.equals(k)) {
    
    
                    oldNodeMap.setV(v);
                }
            }
            oldNode.next = new Node<>(k, v);
        }
    }

    public V get(K k) {
    
    
//        if (k == null) {
    
    
//            for (Entry<K, V> oldEntry = objects[0]; oldEntry != null; oldEntry = oldEntry.next) {
    
    
//                if (oldEntry.k.equals(k)) {
    
    
//                    return oldEntry.v;
//                }
//            }
//        }
        int index = k == null ? 0 : k.hashCode() % objects.length;
        for (Node<K, V> oldEntry = objects[index]; oldEntry != null; oldEntry = oldEntry.next) {
    
    
            if (oldEntry.k == null || oldEntry.k.equals(k)) {
    
    
                return oldEntry.v;
            }
        }
        return null;
    }

    public static void main(String[] args) {
    
    
        ExtHashMap<Object, String> hashMap = new ExtHashMap<>();
        hashMap.put("a", "1212");
        hashMap.put(97, "121212");
        hashMap.put(null, "null");
        System.out.println(hashMap.get("a"));
        System.out.println(hashMap.get(97));
        System.out.println(hashMap.get(null));
    }
}

En el código se utilizan juicios especiales. Juez clave == nula, ¿por qué? Mencionamos antes, la diferencia entre HashMap y HashTable. HashMap permite que la clave sea nula y, cuando la clave es nula, el par clave-valor se almacena en la posición 0 en la tabla de la matriz.
En put (), es necesario juzgar el valor de la clave, si se debe sobrescribir el mismo valor de la clave antes.


Actualización de seguimiento de HashMap en el estado JDK8

Supongo que te gusta

Origin blog.csdn.net/weixin_43911969/article/details/115335872
Recomendado
Clasificación