HashSet、Hashtable的实现

HashSet

首先看一下HashSet的构造函数:

    public HashSet() {
        map = new HashMap<>();
    }

从这个构造函数可以看出,HashSet的实现其实就是利用HashMap,默认情况下采用的是 initial capacity为16,load factor 为 0.75。

再看一下HashSet的add函数:

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

实际上调用的也是HashMap的put函数。只不是放进HashMap里的key值是我们要放进HaseSet里的值,而放进HashMap里的value,就一律都是PRESENT。所以我们使用HashSet,存入HashSet里的元素,其实就是HashMap里的key值。从某种程度上说,HashSet其实就是只取key值的HashMap。

由于HashMap的存储都是通过key值计算hash值来确定存入的坐标,再通过equals方法比较该坐标上已经存在的key,来判断是新存入key-value还是替换value,所以HashMap里的key是唯一不重复的,也就是说HashSet存储的元素也是唯一不重复的。从上面的add方法来看,实际调用了HashMap的put方法。而put方法是,如果存入了key-value的话,返回null,新value替换了旧value的话返回旧value。所以当我们把重复的元素放进HashSet时,map.put(e, PRESENT)就不为null,而add方法得到的返回值就是false。


Hashtable

也先看一下Hashtable的构造方法:

    /**
     * Constructs a new, empty hashtable with a default initial capacity (11)
     * and load factor (0.75).
     */
    public Hashtable() {
        this(11, 0.75f);
    }

    /**
     * Constructs a new, empty hashtable with the specified initial
     * capacity and the specified load factor.
     *
     * @param      initialCapacity   the initial capacity of the hashtable.
     * @param      loadFactor        the load factor of the hashtable.
     * @exception  IllegalArgumentException  if the initial capacity is less
     *             than zero, or if the load factor is nonpositive.
     */
    public Hashtable(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);

        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
        table = new Entry[initialCapacity];
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        initHashSeedAsNeeded(initialCapacity);
    }

在里面可以看到,Hashtable像HashMap一样,都是声明了一个Entry数组,但Hashtable默认的初始容量大小是11,负载因子都是0.75。再看一下Hashtable的put方法:

    /**
     * Maps the specified <code>key</code> to the specified
     * <code>value</code> in this hashtable. Neither the key nor the
     * value can be <code>null</code>. <p>
     *
     * The value can be retrieved by calling the <code>get</code> method
     * with a key that is equal to the original key.
     *
     * @param      key     the hashtable key
     * @param      value   the value
     * @return     the previous value of the specified key in this hashtable,
     *             or <code>null</code> if it did not have one
     * @exception  NullPointerException  if the key or value is
     *               <code>null</code>
     * @see     Object#equals(Object)
     * @see     #get(Object)
     */
    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();  // 如果value为null,则抛出空指针异常
        }

        // Makes sure the key is not already in the hashtable.
        Entry tab[] = table;
        int hash = hash(key);
        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;          // 跟HashMap一样,计算hash值,并且通过equals比较,返回true的就替换
            }
        }

        modCount++;
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
            rehash();

            tab = table;
            hash = hash(key);
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        Entry<K,V> e = tab[index];
        tab[index] = new Entry<>(hash, key, value, e);  // 把新的Entry存储到数组里
        count++;
        return null;
    }

由此可见,Hashtable与HashMap的一个不同点在于,Hashtable会判断value是否为null,而且Hashtable不像HashMap,会把为null的key的hash值用0来代替。所以Hashtable与HashMap的一大不同点是,Hashtable不允许为null的key和value,而HashMap可以。

另外,Hashtable的put方法(基本上所有的方法),都会有synchronized修饰,代表Hashtable是同步的,而HashMap是非同步的。所以如果是涉及到多线程同步时采用 HashTable,不过Collections 类中有一个静态方法:synchronizedMap(),通过该方法也可以得到一个线程安全的 Map 对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值