欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hashtable、Hashset傻傻分不清?

程序员文章站 2022-05-29 11:37:17
...

其实本来说不写这两个类了,但是跟一块心病似的。还是写了吧,把这些不太熟的犄角旮瘩都打扫一遍!

Hashtable

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {

Dictionary是一个废弃类,就不关注它了。可以看到还实现了Map接口,所以是一个键值对结构。Map中无非就是些增删查改的APi,不再赘述。

private transient Entry<?,?>[] table;
 
private transient int count;

private int threshold;

private float loadFactor;

 protected Entry(int hash, K key, V value, Entry<K,V> next) {
            this.hash = hash;
            this.key =  key;
            this.value = value;
            this.next = next;
        }

public V setValue(V value) {
            if (value == null)
                throw new NullPointerException();
}

可以看到基本结构与hashmap一致,底层就是哈希桶,哈希桶中每个桶都是链表,与hashmap的不同就是这里的entry中的value不能为空,会抛出NPE。
其实hashtable真挺没劲的,相关方法都跟hashmap类似,但是都没hashmap写得好。。hashtable想比hashmap唯一的优点可能就是线程安全,每个操作方法都被synchronized锁住了,可是这一锁就把整个entry数组锁住了,锁的粒度太大了,并发性远不如Concurrenthashmap来的好,所以,给个结论,hashtable这玩意儿已经废弃了。。。既没concurrenthashmap好用,也没hashmap来的巧妙。

Hashset

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

可以看到hashset就是个set,即里边没有重复元素

 private transient HashMap<E,Object> map;

    private transient HashMap<E,Object> map;
    
    private static final Object PRESENT = new Object();

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

其内部就是个hashmap,一旦初始化就也将hashmap初始化。这也是其设计巧妙之处,通过hashmap实现元素的唯一性,即每个加入进来的元素都作为key放入hashmap,相对应的value就是这里的PRESENT,即每个元素都是key,value是同一个值。

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

hashmap的put函数会返回该key对应的原来的value,如果原来value不是空,说明对应位置本来就有值,即我们正在加入重复值,返回false,以此来保证hashset中的元素的不可重复。

其他各项方法也是类似,其实就是hashset中包着一层hashmap,巧妙地实现set的不可重复。

公众号:程序员二狗

每日原创文章,一起交流学习!