前言
- 在Java集合中,Map是一种特殊的集合,原因在于这种集合容器并不是保存的单个元素,而是一个个的key-value键值对。HashMap是基于哈希表的Map接口的实现,在项目开发中,这种集合使用是非常广泛的,本文主要就是对HashMap的底层原理做个剖析。
HashMap特点
- HashMap是基于哈希表的Map接口实现。
- HashMap底层采用的是Entry数组和链表实现。
- HashMap是采用key-value形式存储,其中key是可以允许为null但是只能是一个,并且key不允许重复(如果重复则新值覆盖旧值)。
- HashMap是线程不安全的。HashMap存入的顺序和遍历的顺序有可能是不一致的。
- HashMap保存数据的时候通过计算key的hash值来去决定存储的位置。
话不多说上代码
1 package hashMap; 2 3 public class MyHashMap<K, V> { 4 5 private Entry<K, V>[] table;//Entry是hashMap的一个内部类,是真正存放数据的类 6 private static final Integer CAPACITY = 8;// hashMap初始长度 7 private int size;//集合元素的个数 8 9 // 存或修改元素 10 public void put(K k, V v) { 11 //如果是第一次存放,就初始化数组 12 if (table == null) { 13 inflate(); 14 } 15 // 存entry 16 // 根据k的值返回一个int类型的hashCode 17 int hashCode = hash(k); 18 // 根据这个hashCode返回一个数组下标,index是在0~table.length之间的数,不会数组越界 19 int index = indexOf(hashCode); 20 // 如果放入的k已存在,那么将参数k赋值个原先存在的元素,参数v赋值给该元素,达到更新的目的 21 boolean flag = true; 22 for (Entry<K, V> entry = table[index]; entry != null; entry = entry.next) {
//判断是否存在相同的k 23 if (entry.key.equals(k)) { 24 entry.key = k; 25 entry.value = v; 26 flag = false; 27 } 28 } 29 // 如果存在相同的k就不再执行添加方法 30 if (flag) { 31 addEntry(k, v, index); 32 } 33 34 } 35 36 // 取 37 public V get(K k) { 38 // 根据k的值返回一个hashCode 39 int hashCode = hash(k); 40 // 根据这个hashCode返回一个数组下标 41 int index = indexOf(hashCode); 42 // 根据传入的k计算出table数组的下标index,然后循环判断这个index位置是否存在这个k,如果存在就返回该entry的value,如果不存在就返回null 43 for (Entry<K, V> entry = table[index]; table[index] != null; entry = entry.next) { 44 if (entry.key.equals(k)) { 45 return entry.value; 46 } 47 } 48 49 return null; 50 } 51 //添加方法,把最新添加的entry元素放进table数组index位置,把原先在index位置的元素作为新添元素的下一个元素(他的属性) 52 private void addEntry(K k, V v, int index) { 53 Entry<K, V> newEntry = new Entry<>(k, v, table[index]); 54 table[index] = newEntry; 55 // 每存入一个元素数组的元素个数就加一 56 size++; 57 58 } 59 60 private int indexOf(int hashCode) { 61 //用得到的hashCode值对数组长度取模,保证不会现数组越界的错误 62 return hashCode % table.length; 63 } 64 //返回k值的hashcode值 65 private int hash(K k) { 66 67 return k.hashCode(); 68 } 69 //初始化table数组 70 private void inflate() { 71 table = new Entry[CAPACITY]; 72 73 } 74 //内部类,存储数据的实体 75 class Entry<K, V> { 76 private K key; 77 private V value; 78 private Entry<K, V> next; 79 80 public Entry(K key, V value) { 81 82 this.key = key; 83 this.value = value; 84 } 85 86 public Entry(K key, V value, Entry<K, V> next) { 87 88 this.key = key; 89 this.value = value; 90 this.next = next; 91 }100 101 } 102 //测试 103 public static void main(String[] args) { 104 MyHashMap<String, String> myHashMap = new MyHashMap<>(); 105 myHashMap.put("1", "1p"); 106 myHashMap.put("1", "1pp"); 107 myHashMap.put("2", "2p"); 108 System.out.println(myHashMap.get("1"));//1pp,out()方法即是存放又是修改 109 System.out.println(myHashMap.size);//2 110 } 111 112 }