代码已上传到GitHub,有兴趣的同学可以下载来看看:https://github.com/ylw-github/Java-CodeAnalysis-Demo
1. Map接口:
package com.ylw.jdk.hashmap; public interface ExtMap<K, V> { // 向集合中插入数据 public V put(K k, V v); // 根据k 从Map集合中查询元素 public V get(K k); // 获取集合元素个数 public int size(); // Entry的作用=== Node节点 interface Entry<K, V> { K getKey(); V getValue(); V setValue(V value); } }
2. HashMap:
package com.ylw.jdk.hashmap; public class ExtHashMap<K, V> implements ExtMap<K, V> { // 1.定义table 存放HasMap 数组元素 默认是没有初始化容器 懒加载 Node<K, V>[] table = null; // 2. 实际用到table 存储容量 大小 int size; // 3.HashMap默认负载因子,负载因子越小,hash冲突机率越低, 根据每个链表的个数 float DEFAULT_LOAD_FACTOR = 0.5f; // 4.table默认初始大小 16 static int DEFAULT_INITIAL_CAPACITY = 16; // 16 public V put(K key, V value) { // 1.判断table 数组大小是否为空(如果为空的情况下 ,做初始化操作) if (table == null) { table = new Node[DEFAULT_INITIAL_CAPACITY]; } // 2. hashMap 扩容机制 为什么要扩容?扩容数组之后,有什么影响? hahsmap 中是从什么时候开始扩容 // 实际存储大小=负载因子*初始容量=DEFAULT_LOAD_FACTOR0.75*DEFAULT_INITIAL_CAPACITY16=12 // 如果size>12的时候就需要开始扩容数组,扩容数组大小之前两倍 if (size > (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY)) { // 需要开始对table进行属数组扩容 resize(); } // 3.计算hash值指定下标位置 int index = getIndex(key, DEFAULT_INITIAL_CAPACITY); Node<K, V> node = table[index]; if (node == null) { // 没有发生hash冲突问题--- index冲突 node = new Node<K, V>(key, value, null); size++; } else { Node<K, V> newNode = node; while (newNode != null) { // 已经发生hash冲突问题key 直接添加(冲突node)到前面了 不是往后面加 if (newNode.getKey().equals(key) || newNode.getKey() == key) { // hashCodoe 相同,而且equals 相等情况 说明是同一个对象 修改值 // node.value = value; return newNode.setValue(value); } else { // 继续添加,排在前面 hascode 取模余数相同 index 存放在链表 或者hashCode 相同但是对象不同 // 新的node 的next 原来的node if (newNode.next == null) { // 说明遍历到最后一个node ,添加node node = new Node<K, V>(key, value, node); size++; } } newNode = newNode.next; } } table[index] = node; return null; } // 对table进行扩容 private void resize() { // 1.生成新的table 是之前的两倍的大小 DEFAULT_INITIAL_CAPACITY*2 Node<K, V>[] newTable = new Node[DEFAULT_INITIAL_CAPACITY << 1]; // 2.重新计算index索引,存放在新的table里面 for (int i = 0; i < table.length; i++) { // 存放在之前的table 原来的node Node<K, V> oldNode = table[i]; // a 的index=1 b 的index=1 // a ## while (oldNode != null) { table[i] = null;// 赋值为null---为了垃圾回收机制能够回收 将之前的node删除 // 存放在之前的table 原来的node key K oldK = oldNode.key; // 重新计算index int index = getIndex(oldK, newTable.length); // 存放在之前的table 原来的node next if (oldK.equals("22号") || oldK.equals("66号")) { System.out.println("日志记录"); } Node<K, V> oldNext = oldNode.next; // 如果ndex 下标在新newTable发生相同的index时候,以链表进行存储 // // 原来的node的下一个是最新的(原来的node存放下新的node下一个) oldNode.next = newTable[index]; // 将之前的node赋值给 newTable[index] newTable[index] = oldNode; // 判断是否继续循环遍历 oldNode = oldNext; } } // 3.将newtable赋值给老的table table = newTable; DEFAULT_INITIAL_CAPACITY = newTable.length; newTable = null;/// 赋值为null---为了垃圾回收机制能够回收 } private String age; public int getIndex(K k, int length) { int hashCode = k.hashCode(); // System.out.println("k:" + k + ",hashCode=" + hashCode); int index = hashCode % length; return index; } public V get(K k) { Node<K, V> node = getNode(table[getIndex(k, DEFAULT_INITIAL_CAPACITY)], k); return node == null ? null : node.value; } public Node<K, V> getNode(Node<K, V> node, K k) { while (node != null) { if (node.getKey().equals(k)) { return node; } node = node.next; } return null; } public int size() { return size; } // 定义节点 class Node<K, V> implements Entry<K, V> { // 存放Map 集合 key private K key; // 存放Map 集合 value private V value; // 下一个节点Node private Node<K, V> next; public Node(K key, V value, Node<K, V> next) { super(); this.key = key; this.value = value; this.next = next; } public K getKey() { return this.key; } public V getValue() { return this.value; } public V setValue(V value) { // 设置新值的返回老的 值 V oldValue = this.value; this.value = value; return oldValue; } } }