HashSet、Hashtable与HashMap的关系

HashSet、Hashtable与HashMap的关系

一.HashSet与HashMap的关系

 

       阅读HashSet的源代码,发现加上很多注释总共就只有300多行,所以就可以猜到它的内部实现一定借助了其他的数据结构。事实上,它就是在HashMap的基础上实现的。在它的内部,包含了一个HashMap。

privatetransient HashMap<E,Object> map;

 

  它的构造方法其实也是直接调用了HashMap的构造方法。

 

publicHashSet() {

    map = new HashMap<>();

}

  再来看一看它的add方法。

 

publicboolean add(E e) {

        return map.put(e, PRESENT)==null;

    }

 

        其实就是调用了HashMap的put方法,key就是加入的e,value为PRESENT,它是HashSet内部的一个成员变量,就是一个空的Object对象。

privatestatic final Object PRESENT = new Object();

 

       它是一个虚值,作用就是为了作为value与HashMap关联。add方法的返回值类型是boolean。通过上次分析的HashMap源码可以知道,当放入的key值在HashMap的table数组中不存在时,即没有hash冲突时,会把新元素加入数组中,同时返回null.所以这种情况下,add方法的返回值就是ture,表示进行了增加的操作。当放入的key,即HashSet要加入的e已经在HashMap的table数组中存在时,会用新的value覆盖旧的value,对于HashSet来说,就是用新的PRESENT替换了旧的PRESENT。然后直接返回旧的value值,并没有进行HashMap的插入操作。所以这个时候的add方法放入返回值就是false,表示HashSet没有大小以及元素的改变。

 

       相似的,HashSet的remove方法也是直接调用了HashMap的remove方法

publicboolean remove(Object o) {

        return map.remove(o)==PRESENT;

    }

 

       由于HashMap的remove方法当size为0或者要删除的元素不存在时,会返回null,所以这时add方法的返回值就是false,表示没有进行删除的操作,HashSet没有发生改变。当要删除的元素存在时,HashMap的remove方法会返回value的值,由于在HashSet中,所有的value都是PRESENT这一个对象,所以这个时候add的返回值就是true,表示HashSet进行了删除的操作,发生了改变。

 

 

二.Hashtable与HashMap的关系

   

      首先发现一个比较有趣的细节问题,就是Hashtable的t没有大写,没有遵循java类命名的驼峰规则。不知道什么原因。

然后一个比较大的区别是他们的父类不同。

HashMap<K,V>  extendsAbstractMap<K,V>

Hashtable<K,V>  extendsDictionary<K,V>

 

        他们的底层实现都是Entry数组,但是他们的初始默认的大小不一样,HashMap中默认的大小是16,而Hashtable的默认大小确是11,但是他们的默认负载因子都是0.75.下面为他的无参的构造方法:

public Hashtable() {

        this(11, 0.75f);

    }

 

        然后他们的求数组下标的哈希映射的算法实现不一样,HashMap使用的是&运算,效率相对要高一些。而Hashtable使用的是取模的余数运算。

int index = (hash & 0x7FFFFFFF) % tab.length;

 

 

          他们最大的区别就是Hashtable中所有的可能导致线程安全问题的方法都使用了synchronized修饰,加了互斥锁。所以说Hashtable是线程安全的。但是缺点就是效率很低。他们的区别就好像Vector和ArrayList。他们还有很多的细节上的区别,大家无聊的时候可以去看看。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章