源码分析系列教程(12) - 手写Map框架(基于JDK1.7)

简介: 源码分析系列教程(12) - 手写Map框架(基于JDK1.7)

代码已上传到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;
        }
    }
}


目录
相关文章
|
6月前
|
存储 安全 Java
【JDK 源码分析】ConcurrentHashMap 底层结构
【1月更文挑战第27天】【JDK 源码分析】ConcurrentHashMap 底层结构
|
6月前
|
Java
【JDK 源码分析】HashMap 操作方法
【1月更文挑战第27天】【JDK 源码分析】HashMap Put 元素 初始化
|
1月前
|
Java
Java基础之 JDK8 HashMap 源码分析(中间写出与JDK7的区别)
这篇文章详细分析了Java中HashMap的源码,包括JDK8与JDK7的区别、构造函数、put和get方法的实现,以及位运算法的应用,并讨论了JDK8中的优化,如链表转红黑树的阈值和扩容机制。
24 1
|
1月前
|
Oracle Java 关系型数据库
jdk17安装全方位手把手安装教程 / 已有jdk8了,安装JDK17后如何配置环境变量 / 多个不同版本的JDK,如何配置环境变量?
本文提供了详细的JDK 17安装教程,包括下载、安装、配置环境变量的步骤,并解释了在已有其他版本JDK的情况下如何管理多个JDK环境。
729 0
|
2月前
|
人工智能 Java 测试技术
JDK11下Mock框架进化:从PowerMockito到Mockito Only
本文探讨了从使用PowerMock的测试环境迁移到仅使用Mockito(Mockito Only)策略的必要性和实践方法。
|
3月前
|
Java
JDK序列化原理问题之Hessian框架不支持writeObject/readObject方法如何解决
JDK序列化原理问题之Hessian框架不支持writeObject/readObject方法如何解决
WXM
|
4月前
|
Oracle Java 关系型数据库
Java JDK下载安装及环境配置超详细图文教程
Java JDK下载安装及环境配置超详细图文教程
WXM
650 3
|
5月前
|
前端开发 Java 应用服务中间件
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
Spring框架第六章(SpringMVC概括及基于JDK21与Tomcat10创建SpringMVC程序)
|
5月前
|
Oracle Java 关系型数据库
Java官网下载JDK21版本详细教程(下载、安装、环境变量配置)
Java官网下载JDK21版本详细教程(下载、安装、环境变量配置)
|
4月前
|
JavaScript 定位技术
vue 百度地图开发【教程】1. 绘制百度地图(不使用 vue-baidu-map,解决 BMap is undefined)
vue 百度地图开发【教程】1. 绘制百度地图(不使用 vue-baidu-map,解决 BMap is undefined)
407 0

相关实验场景

更多