HashMap源码实现
来源:互联网 发布:石家庄蓝点网络 编辑:程序博客网 时间:2024/06/18 08:37
HashMap存储格式
首先来看看HashMap的数据存储格式:
从本质上来说,hashMap实际上是一个数组,数组的每个元素称为一个Node,这个Node实际上是一个链表,每个对象的hash值经过一些处理作为数组的key,hashMap通过key定位到数组对应的位置。当两个对象的hash值相同的时候,就会在链表的next元素进行拓展。
源码
本文主要要实现hashMap的put、get、扩容方法;
基本代码架构:
public class MyHashMap<K,V> { //数组的初始大小 static final int DEFAULR_INITIAL_CAPACITY=16; //安全因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; //扩容因子 static final int DEFAULT_DITATATION_FACROT=2; private int size = 0; //数组元素 private Node<K,V> table[] = null; public V put(){ return null; }; public V get(){ return null; } //Map的大小 public int size(){ return this.size; } //提供hash算法,确定Node在数组中的位置 private int indexOf(Object o){ return 0; } //扩容方法 private void dilatation() { } public class Node<K,V> implements Entry<K, V>{ @Override public K getKey() { return null; } @Override public V getValue() { return null; } @Override public V setValue(V value) { return null; } }}
关于构造
前面已经说过,数组的元素是由节点Node
private class Node<K,V> implements Entry<K, V>{ //Node在数组中的位置,根据对象的hash值确定 private int index; private K key; private V value; //当hash值出现冲突以后,往链表中插入对象 private Node<K,V> next; public Node(int index, K key, V value, Node<K, V> next) { super(); this.index = index; this.key = key; this.value = value; this.next = next; } @Override public K getKey() { return null; } @Override public V getValue() { return null; } @Override public V setValue(V value) { return null; } }
下面来看看HashMap的构造:
private Node<K,V> table[] = null; //创建一个大小为默认值的数组 public MyHashMap() { table = new Node[DEFAULR_INITIAL_CAPACITY]; }
hash算法indexOf方法实现:
//提供hash算法,确定Node在数组中的位置 public int indexOf(K key){ //与数组length-1取模,确定返回值不大于数组的length-1 return hash(key) % (table.length-1); } //让hash值无符号右移16位,缩小hash值 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
源码实现
put方法实现:
public V put(K key,V value){ //tab用来指向table,p当前数组位置的Node; Node<K, V> tab[] = table; Node<K,V> p; int i = indexOf(key); p = table[i]; if(p == null){ //如果数组的该位置没有元素 p = new Node<K, V>(i, key, value, null); tab[i] = p; return value; }else{ //如果数组的该位置有元素 Node<K,V> e;//用于判断key是否相同,是否需要覆盖 if(p.index == indexOf(key)&&(p.key==key||key.equals(p.key))){ //key相同(这里我们可以看到map判断key是否相同需要他的hash值和equals都相同) e = p; }else{ //对p进行遍历 for(int count = 0 ; ; ++count){ if((e=p.next)==null){ //如果p链表没有后续元素 p.next = new Node<K,V>(indexOf(key), key, value, null); break; } //如果链表中其他元素的key有相同的 if(e.index==indexOf(key)&&(e.key==key||e.key.equals(key))){ break; } //如果链表有后续元素,并且key和链表当前位置的元素key不用,将p指向p.next p= e; } } //key有覆盖的情况出现,将key对应的value进行覆盖处理 if(e!=null){ e.value = value; return value; } //e==null则没有覆盖情况 size++; if(size>DEFAULR_INITIAL_CAPACITY*DEFAULT_LOAD_FACTOR){ //扩容; dilatation(); } } return value; };
get方法实现:
public V get(K key){ Node<K,V> tab[] ; Node<K,V> e ; tab = table; int index = indexOf(key); e = tab[index]; //该key没有值 if(e == null){ return null; }else{ //遍历Node e do { //获取e的值 if(key==e.key||key.equals(e.key)){ return e.value; } } while ((e=e.next)!=null); } return null; }
扩容方法dilatation
//扩容方法 private void dilatation() { Node<K, V> oldNode[] = table; int oldCount = table.length; //将容量扩张到两倍 int newCount = oldCount*DEFAULT_DITATATION_FACROT; Node<K, V> newNode[] = new Node[newCount]; table = newNode; for(int i = 0 ; i < oldCount ; i++){ if(oldNode[i]!=null){ Node<K,V> e = oldNode[i]; Node<K,V> tmp = oldNode[i]; //给newNode赋值,修改Node的index值 int newIndex = indexOf(tmp.getKey()); do { tmp.index = newIndex; } while ((tmp=tmp.next)!=null); newNode[newIndex] = e; } } }
1 0
- HashMap源码实现
- java源码:HashMap实现原理
- 从源码分析HashMap实现
- HashMap设计原理、HashMap的数据结构、HashMap源码实现
- Java中HashMap详解 - HashMap源码及实现原理
- HashSet和HashMap源码实现分析
- java hashmap的put函数实现源码
- JDK源码阅读之HashMap的实现
- HashMap的实现原理及源码
- java中hashmap源码分析和实现
- Java集合之HashMap源码实现分析
- HashMap实现原理以及源码阅读
- HashMap实现原理及源码分析
- Java源码---HashMap的底层实现
- HashMap内部实现及源码分析
- HashMap实现原理及源码分析
- Java集合之HashMap源码实现分析
- JDK源码阅读:实现自己的HashMap
- ROS+P3DX代码注解 [ 1 ] -- RosAria_client代码注解
- 【Java基础】Java变量
- opencv之形态学重建
- jvisualvm远程监控Tomcat
- sass & compass总结(一)
- HashMap源码实现
- node编写一个简单的服务器
- 常用数据库连接池 (DBCP、c3p0、Druid) 配置说明
- php(二)
- 全志B288驱动2-按键功能修改
- /dev/fb0入门练习(linux FrameBuffer)
- 北京理工大学2004年机试第二题
- WFDB 中bxb提取annotator中的数据
- [经典]RXJava给 Android 开发者的 RxJava 详解