zoukankan      html  css  js  c++  java
  • Java Se :Map 系列

     之前对Java Se中的线性表作了简单的说明。这一篇就来看看Map。

    Map系列的类,并不是说所有的类都继承了Map接口,而是说他们的元素都是以<Key, Value>形式设计的。

    Dictionary

    这个类现在不推荐使用了,但也有必要说一下,在它的描述中,有这么一句:Any non-null object can be used as a key and as a value。

    现在都改用Map接口了。

    Map

    这个接口用于替换Dictionary的。这种集合提供了三种视图方式:

    1)a set of keys

    2)collection of Values

    3)set of Entry<key, value>

    Hashtable

    这个类继承了Dictionary实现了Map。下面就重点看看这个类如何实现。

     

    从这里看Hashtable是一个数组,数组的元素是Entry。

    在看看Entry的设计:

     

    这个Entry是一个单链表。

    所以Hashtable的数据结构就可以认为是这样的:

     

    为什么会这样设计?

    以为硬件的原因,支持数组和链表两种形式,所以其他的数据结构(集合)都是基于这两类基础结构实现的。

    Hashtable的设计,关键一点是hash,它计算的是key的hash,通过key的hashcode来计算这个元素所在的单链表在数组中的索引,然后根据索引取到单链表,然后进行其他的操作。

    接下来看看它的几个重要方法如何实现:

    put

    public synchronized V put(K key, V value) {
    
       // Make sure the value is not null
    
       if (value == null) {
    
           throw new NullPointerException();
    
       }
    
     
    
       // 如果key已经在这个hashtable中存在,就覆盖原有的value,并返回原有的value。
    
       // 从这一小段代码中,我们就可以看出hashtable的结构确实如上面所想的那样。
    
    Entry tab[] = table;
    
       int hash = key.hashCode();
    
       int index = (hash & 0x7FFFFFFF) % tab.length;
    
       for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
    
           if ((e.hash == hash) && e.key.equals(key)) {
    
          V old = e.value;
    
          e.value = value;
    
          return old;
    
           }
    
       }
    
     
    
       modCount++;
    
       if (count >= threshold) {
    
           // Rehash the table if the threshold is exceeded
    
           rehash();
    
     
    
                tab = table;
    
                index = (hash & 0x7FFFFFFF) % tab.length;
    
       }
    
     
    
       // 如果不存在,就把key value 封装成一个Entry,然后插入到相应位置
    
    // 在之前的代码中已经计算出它的索引了,接下来的任务就是把entry插入到数组索引位置处的单链表里。插入的时候是从头部插入的。
    
      Entry<K,V> e = tab[index];
    
       tab[index] = new Entry<K,V>(hash, key, value, e);
    
       count++;
    
       return null;
    
        }
    
     
    Hashtable#put(key, value)

      

    常用的方法get(key),remove(key)的方法就不分析了,因为没有必要,只要你了解了这个数据结构,自己就可以实现它的几个常用的方法。

    keys

     

     

    拿到的结果其实是一个枚举器(不过这个枚举器比较特殊,实现了Enumeration接口和Iterable接口),并不是一个集合。

    同样的道理,elements也是如此,拿到的结果是一个遍历value的枚举器。

    HashMap

    HashMap的存储结构如下图所示,因为源码部分太多,所以就截了这么一张图,但也足够说明问题了:

     

    从图上很容易看出,HashMap也是使用了数组实现的,数组中的元素是Node,再看看Node的设计:

     

    Node也是一个单链表,看来HashMap与Hashtable在结构上是基本一致的。

    也就是说他的模型也是下面图中所示:

     

    如果说HashMap的结构只是这个样子的话,就没有必要存在了。为什么这么说呢,关键点还是在Node上,看看他的两个子类:

     

    Entry:

    每个节点又添加了一两个引用:before,after,这样一来结构就可以猜想为:

    但其实并不是这个样子的,会根据hashcode进行一些算法处理,形成链式结构,也就是LinkedHashMap了。

    如果有兴趣可以了解一些LinkedHashMap是如何实现的。

    TreeNode:

     

    每个节点都可以是一个树。就让结构变得更为复杂了。

  • 相关阅读:
    Linux(CentOS)下squid代理服务器配置-五岳之巅
    用类实现二叉树
    django--02 模板的使用
    django --01 helloworld样例入门
    微指数爬虫
    celery_01 _celery安装启动
    python多线程几种方法实现
    crontab问题处理
    python可视化--matplotlib
    python网页爬虫--京东家电版块
  • 原文地址:https://www.cnblogs.com/f1194361820/p/3994625.html
Copyright © 2011-2022 走看看