Hashtable是同步的。 如果不需要线程安全的实现,建议使用HashMap代替Hashtable 。 如果需要线程安全的并发实现,那么建议使用ConcurrentHashMap代替Hashtable

打开Hashtable的源码可以看见

1、Hashtable底层存放数据的其实是他的一个内部类的数组,在创建Hashtable实例的时候,需要指定这个数组的长度,默认是11,源码如下:

//无参构造方法
public Hashtable() {
        this(11, 0.75f);
    } 
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是具体放值的数组,设置长度是传入参数initialCapacity,期默认值是11
        //Entity是一个被私有了的内部类
        table = new Entry<?,?>[initialCapacity];
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }
 private static class Entry<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Entry<K,V> next;

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

        @SuppressWarnings("unchecked")
        protected Object clone() {
            return new Entry<>(hash, key, value,
                                  (next==null ? null : (Entry<K,V>) next.clone()));
        }

        // Map.Entry Ops

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

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

            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;

            return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
               (value==null ? e.getValue()==null : value.equals(e.getValue()));
        }

        public int hashCode() {
            return hash ^ Objects.hashCode(value);
        }

        public String toString() {
            return key.toString()+"="+value.toString();
        }
    }
Entry 类源码

2、因为Hashtable是通过Entity数组存值的,且Entity有一个属性是专门放其数组中下一个值的Entity对象的,所以,查找起来更快,查找方法源码如下:

public synchronized V get(Object key) {
        Entry<?,?> tab[] = table;
        // 计算出key对应的hash值
        int hash = key.hashCode();
         // 使用key对应hash值算出一个数值来,使其在数组数组长度范围内,用来作为查找开的的索引
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return (V)e.value;
            }
        }
        return null;
    }

3、通过put方法源码看到存值时只对value做了非空校验,且如果key对应的位置已经存有值,将会覆盖后返回老值

4、通过源码看如果找到了返回老值,没找到,返回null。

5、其线程安全的实现方式是在每个操作方法上都添加了synchronized同步锁,是的对其进行操作的时候要有获得锁和释放锁的操作,所以如果不需要线程安全最好不要用他。

6、java1.5之后,java为线程安全key&value集合提供了一个ConcurrentHashMap,它的实现思路和HashTable基本类似,不过在其基础上又做了很多优化。例如,他的同步锁不是加载方法上的,而是加在代码块上的,通过key计算hashcode的时候除了调用object的hashcode方法外还做了(h ^ (h >>> 16)) & HASH_BITS;位移后的与操作。

7、通过debug的时候发现,在实际使用hashTable时,java给我们加了层代理,而且不止java加了,不同的运行环境也有不同的处理。

 

 打开代理方法都是被native关键字修饰了。而期创建的hashTable对象也是其子类Properties的对象

posted @ 2020-01-19 16:35  田海超  阅读(418)  评论(0编辑  收藏  举报