• hashMap的具体实现


    HashMap是Java中的一个重要的数据结构!

    与HashMap更重要的一个数据结构是HashTable,其中最重要的区别是HashTable传说中是线程安全的(之所以说他是传说是因为我并没有去理解为什么,这是我的错,没有理解就搬上了讲台!)

    HashMap的内部结构很简单,如下(图片来自importnews,专属java的一个实时blog.本文也一定程度上参考了importnews,之所有没有直接转载是因为我觉得,有些东西,你只是看到了,他并不属于你!而我要做的,就是消化它,达到可以有自己见解的地方,原文链接地址:http://www.importnew.com/10620.html)

    在HashMap内部,实现存贮key-value键值对的是一个Entity的内部类,

    static class Entry implements Map.Entry
    {
            final K key;
            V value;
            Entry next;
            final int hash;
            ...//More code goes here
    }   `

    这个类可以构成一个链表,在key中的hashCode相同时,会构成一个链表,

    这个类在HashMap中构成了一个table数组,所有的键值对就保留在这个键值对数组之中,这个数据默认的长度是16,当数据超过这个大小之后,会自动的真正增长,但是如果数据刚刚好处于增长的上边缘,也就是>=,会造成数据内存大浪费,一些文章推荐我们在使用一些集合类的时候要指定好它的大小,避免造成过大的内存泄漏

    从我们平常使用的HashMap中我们可以得出,操纵HashMap只是通过put和get方法

    1.了解put方法

     public V put(K key, V value) {
      if (key == null)
       return putForNullKey(value);
      int hash = hash(key.hashCode());
      int i = indexFor(hash, table.length);
      for (Entry<k , V> e = table[i]; e != null; e = e.next) {
       Object k;
       if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
        V oldValue = e.value;
        e.value = value;
        e.recordAccess(this);
        return oldValue;
       }
      }
     
      modCount++;
      addEntry(hash, key, value, i);
      return null;
     }
    1. 对key做null检查。如果key是null,会被存储到table[0],因为null的hash值总是0。

    2. key的hashcode()方法会被调用,然后计算hash值。hash值用来找到存储Entry对象的数组的索引。有时候hash函数可能写的 很不好,所以JDK的设计者添加了另一个叫做hash()的方法,它接收刚才计算的hash值作为参数。如果你想了解更多关于hash()函数的东西,可 以参考:hashmap中的hash和indexFor方法

    3. indexFor(hash,table.length)用来计算在table数组中存储Entry对象的精确的索引。

    4. 在我们的例子中已经看到,如果两个key(这里指的是两个不同key值)有相同的hash值(也叫冲突),他们会以链表的形式来存储。所以,这里我们就迭代链表。

    • 如果在刚才计算出来的索引位置没有元素,直接把Entry对象放在那个索引上。
    • 如果索引上有元素,然后会进行迭代,一直到Entry->next是null。当前的Entry对象变成链表的下一个节点。
    • 如果我们再次放入同样的key会怎样呢?逻辑上,它应该替换老的value。事实上,它确实是这么做的。在迭代的过程中,会调用equals() 方法来检查key的相等性(key.equals(k)),如果这个方法返回true,它就会用当前Entry的value来替换之前的value。

    2.了解get

    public V get(Object key) {
      if (key == null)
       return getForNullKey();
      int hash = hash(key.hashCode());
      for (Entry<k , V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
       Object k;
       if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
        return e.value;
      }
      return null;
     }

    你传递一个key从hashmap总获取value的时候:

    1. 对key进行null检查。如果key是null,table[0]这个位置的元素将被返回。

    2. key的hashcode()方法被调用,然后计算hash值。

    3. indexFor(hash,table.length)用来计算要获取的Entry对象在table数组中的精确的位置,使用刚才计算的hash值。

    4. 在获取了table数组的索引之后,会迭代链表,调用equals()方法检查key的相等性,如果equals()方法返回true,get方法返回Entry对象的value,否则,返回null。

    总结:

    • HashMap有一个叫做Entry的内部类,它用来存储key-value对。
    • 上面的Entry对象是存储在一个叫做table的Entry数组中。
    • table的索引在逻辑上叫做“桶”(bucket),它存储了链表的第一个元素。
    • key的hashcode()方法用来找到Entry对象所在的桶。
    • 如果两个key有相同的hash值,他们会被放在table数组的同一个桶里面。
    • key的equals()方法用来确保key的唯一性。
    • value对象的equals()和hashcode()方法根本一点用也没有。
  • 相关阅读:
    decode函数
    自我介绍
    语法》第六章 数组
    语法》第二章 数据类型
    语法》第四章 字符串
    语法》第七章 函数
    取模和取余的区别
    语法》第五章 对象
    语法》第三章 数值
    语法》第一章 基本语法
  • 原文地址:https://www.cnblogs.com/rainiplus/p/3721998.html
Copyright © 2020-2023  润新知