依然是先上翻译
这个类实现了从键映射到值的哈希表。任何非null的对象都可以成为键或者是值。
为了在哈希表中成功的存入和取出对象,作为key的对象必须实现hashcode方法和equals方法
一个哈希表的实例的性能被两个因素影响:初始容量和加载因子。容量是哈希表中桶的数量,初始容量就是哈希表创建时候的容量。哈希表是开放的,当遇到哈希冲撞的时候,一个桶会装着多个项,这些项必须被顺序的搜索。加载因子表示哈希表内装了百分之多少会自动增长容量。初始容量和负载系数参数仅仅是实现的提示。 关于何时以及是否调用rehash方法的确切细节是依赖于实现的。
通常来说,默认的加载因子0.75提供了空间和时间上的平衡。更高的值降低了空间的开销但提高了查找项的时间开销。
初始容量控制了浪费空间和非常浪费时间的重新哈希的平衡。如果哈希表的初始大小大于最大数目除以加载因子,则不会发生重新哈希操作。然而,把初始容量设的太高会浪费空间
如果很多的项会被放到哈希表中,创造时设定充分大的容量会让项插入时更加高效,而不是让容量自动的重新哈希并增长
基本都跟hashmap差不多,直接上最后一段最重要的
hashtable是同步的,如果不需要线程安全的实现,推荐使用hashmap而不是hashtable,如果需要线程安全高并发的实现,推荐使用concurrenthashmap
下面是代码辣
class Hashtable
成员变量transient Entry,?>[] table;//哈希桶列表
成员变量transient int count;//表示装了多少项
成员变量int threshold;//当项的数目超过了这阈值就会发生重新hash,是容量乘以重新哈希得到的值
成员变量float loadFactor;//加载因子
成员变量transient int modCount = 0;
此Hashtable已被结构修改的次数结构修改是指更改Hashtable中的条目数或以其他方式修改其内部结构(例如,重新散列)的修改。 此字段用于在Hashtable的Collection-views上快速生成迭代器。 (请参阅ConcurrentModificationException)。
构造函数Hashtable(int initialCapacity, float loadFactor)
判参数合法;然后容量加载因子赋值,根据容量来初始化桶的数组,计算重新哈希的阈值
构造函数Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); }
构造函数Hashtable() { this(11, 0.75f); }
构造函数Hashtable(Map extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); }//就是复制一个哈希表并且让新的哈希表容量翻倍
看不懂的操作Hashtable(Void dummy) {}//注释说仅仅创建这对象
方法synchronized int size() { return count; }
方法synchronized boolean isEmpty() { return count == 0; }
方法synchronized Enumeration
返回此哈希表中键的枚举。 在返回的对象上使用Enumeration方法按顺序获取密钥。 如果在枚举键的同时对哈希表进行结构修改,那么枚举的结果是未定义的。
核心方法synchronized boolean contains(Object value)
从最后一个桶开始遍历,对桶内的每个元素线性遍历
方法boolean containsValue(Object value) { return contains(value); }
核心方法synchronized boolean containsKey(Object key)
调用key的hashcode方法获取到hash后,int index = (hash & 0x7FFFFFFF) % tab.length;拿到key对应的桶序号,对桶内元素线性遍历
核心方法synchronized V get(Object key)
同上拿到桶号后,线性遍历拿到对应的value
成员变量static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
要分配的最大数组大小。 一些VM在阵列中保留一些标题字。 尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制,注释都看不懂
核心方法void rehash()
先拿到现在的桶数量;然后用一个entry数组装着现在的table;
新的容量是现在容量的2倍+1;如果新的容量大于MAX_ARRAY_SIZE且现在的容量等于MAX_ARRAY_SIZE,直接返回;负责新的容量等于MAX_ARRAY_SIZE;
根据新的容量来初始化桶列表table,递增modcount,重新计算阈值
对原来桶内的每个元素进行int index = (e.hash & 0x7FFFFFFF) % newCapacity;然后得到新的桶号,然后放到新的桶里的第一个,新桶里的元素放这个元素后面
核心方法void addEntry(int hash, K key, V value, int index)
如果桶里的项已经超过了阈值,调用重新哈希,然后重新计算插入key的哈希值和应该放入的桶号;
然后根据桶号,把新的项放到桶里第一个,桶里原有的项放到这个元素后面
核心方法synchronized V put(K key, V value)
根据插入的key算出哈希值然后找到对应的桶号,线性遍历桶内每一个元素,如果原来已经存在这个key了,替换旧的value;否则调用addEntry
核心方法synchronized V remove(Object key)
计算桶号,线性遍历桶内,找到元素后,如果有前一个元素,前一个元素指向这元素的后一个元素,否则桶内第一个元素指向后一个元素,返回旧的value,递增modcount,递减count;如果不存在就返回null;
方法synchronized void putAll(Map extends K, ? extends V> t)
遍历t内元素,调用put(e.getKey(), e.getValue());
方法synchronized void clear()
把每个桶第一个元素指向null;递增modcount
方法synchronized Object clone()
应该是创建一个新的hashtable,然后深复制一份当前hashtable的元素
方法Hashtable,?> cloneHashtable()调用父类的clone()方法
方法synchronized String toString()
遍历生成{key1=value1,key2=value2}格式的字符串
方法
如果没有元素,返回 Collections.emptyEnumeration();;否则返回new Enumerator<>(type, false);(后面会讲到这个内部类)
方法
同上,只是没有元素时返回的是Collections.emptyIterator();
成员变量
private transient volatile Set
private transient volatile Set
private transient volatile Collection
注释初始化每个字段以在第一次请求此视图时包含相应视图的实例。 视图是无状态的,因此没有理由创建多个视图。
核心方法Set
如果keyset是null,赋值为Collections.synchronizedSet(new KeySet(), this);;返回keySet
注释返回此映射中包含的键的{@link Set}视图。 该集由map支持,因此对map的更改将反映在集中,反之亦然。 如果在对集合进行迭代时修改了映射(除非通过迭代器自己的{@code remove}操作),则迭代的结果是未定义的。 该集支持元素删除,它通过{@code Iterator.remove},{@ code Set.remove},{@ code removeAll},{@ code retainAll}和{@code clear从map中删除相应的映射。 操作。 它不支持{@code add}或{@code addAll}操作。
内部类class KeySet extends AbstractSet
内部类中的常规方法
public Iterator
public int size() { return count; }
public boolean contains(Object o) { return containsKey(o); }
public boolean remove(Object o) { return Hashtable.this.remove(o) != null; }
public void clear() { Hashtable.this.clear(); }
核心方法Set
如果entryset为null,赋值为entrySet = Collections.synchronizedSet(new EntrySet(), this);;返回entryset
注释返回此映射中包含的映射的{@link Set}视图。 该集由map支持,因此对map的更改将反映在集中,反之亦然。 如果在对集合进行迭代时修改了映射(除了通过迭代器自己的{@code remove}操作,或者通过迭代器返回的映射条目上的{@code setValue}操作),迭代的结果 未定义。 该集支持元素删除,它通过{@code Iterator.remove},{@ code Set.remove},{@ code removeAll},{@ code retainAll}和{@code clear}从map中删除相应的映射。操作。 它不支持{@code add}或{@code addAll}操作。
内部类class EntrySet extends AbstractSet
常规方法
public Iterator
public boolean add(Map.Entry
public int size() { return count; }
public void clear() { Hashtable.this.clear(); }
内部类方法boolean contains(Object o)
如果o不是map.entry的实例,返回false;强转型为map.entry然后获得key,计算hash和对应的桶号,线性遍历桶内元素
内部类方法boolean remove(Object o)
找的方法同上,找到之后判断是否桶内第一个元素,如果是桶内第一个元素,桶内第一个元素指向第二个元素;如果不是桶内第一个元素,前一个元素指向后一个元素,递增modcount;细节 把清除项的value指向null,注释说为了gc
方法 Collection
判断values是否为null,如果是null,赋值为Collections.synchronizedCollection(new ValueCollection(), this);;返回values
内部类class ValueCollection extends AbstractCollection
常规方法
public Iterator
public int size() { return count; }
public boolean contains(Object o) { return containsValue(o); }
public void clear() { Hashtable.this.clear(); }
核心方法synchronized boolean equals(Object o)
如果o等于this返回true;如果o不是map的实例,返回false;o强转型为map,如果size()不等,返回false;从this的entrySet中逐项取出元素,value为null的元素,在传入的对象中判断key是否存在以及对应的value是否为null;value不为null的元素,判断从传入对象中用keyget到的对象是否相同
核心方法synchronized int hashCode()
如果没有元素或加载因子小于0,返回0;加载因子乘以-1,表示正在计算hash;对每个桶中的每个元素的hashcode进行累加;完成后加载因子再乘以-1,表示计算完hash
常规方法synchronized V getOrDefault(Object key, V defaultValue)
如果key对应的value是null,返回defaultValue,否则返回key对应的value
方法synchronized void forEach(BiConsumer super K, ? super V> action)
对action进行判空;记录下开始时候的modcount;对每个桶内的每个元素都进行action.accept((K)entry.key, (V)entry.value);,每进行一次就判断一次modcount是否被改变,被改变抛出异常
方法synchronized void replaceAll(BiFunction super K, ? super V, ? extends V> function)
跟上面一样,核心的一句换成了entry.value = Objects.requireNonNull( function.apply(entry.key, entry.value));
方法synchronized V putIfAbsent(K key, V value)
对传入的value判空,通过key计算桶号,线性遍历桶内每一个元素,如果找到相同的key,并且对应的value是null,用传入的value代替,返回旧的value;如果不存在相同的key,执行addEntry(hash, key, value, index);
方法synchronized boolean remove(Object key, Object value)
对value判空,计算桶号,桶内元素线性遍历,找到之后判断是不是第一个元素,如果是将桶的第一个元素指向第二个元素;如果不是将前一个元素指向后一个元素;value指向null方便gc
方法synchronized boolean replace(K key, V oldValue, V newValue)
新旧value判空,key确定桶号,线性遍历桶内,找到对应的旧key和旧value,换成新的value
方法synchronized V replace(K key, V value)
跟上面一样,只是找到key之后无脑替换
方法synchronized V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction)
对参数判空,key对应桶号,线性遍历桶内,如果找到了key,返回key对应的value;记录modecount,执行V newValue = mappingFunction.apply(key);然后判断modcount是否被改变,如果新的value不是null执行addEntry(hash, key, newValue, index);
方法synchronized V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction)
参数判空算桶号线性遍历,如果找到了key,记录modecount执行V newValue = remappingFunction.apply(key, e.value);再看modcount;如果新的值为空,则把当前元素从桶内移除,递增modcount递减count;如果新的值不为null,修改旧的值
方法synchronized V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction)
参数判空算桶号线性遍历;如果在桶内找到了key、,记录modcount执行V newValue = remappingFunction.apply(key, e.value);判断modcount;如果新值为null则当前元素从桶内移除,递增modcount递减count;如果不为null则改变value;如果桶内找不到key,则通过参数计算value,如果算出value不为null,执行addEntry(hash, key, newValue, index);
方法synchronized V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction)
参数判空算桶号线性遍历;找到key之后,V newValue = remappingFunction.apply(e.value, value);如果新值为null则移除,否则替换;如果找不到且传入的value不为null,执行、addEntry(hash, key, value, index);
然后就是一些序列化方法了
再然后是内部类static class Entry
内部类成员变量
final int hash; final K key; V value; Entrynext;
常规构造函数
方法Object clone() { return new Entry<>(hash, key, value, (next==null ? null : (Entry
public K getKey() { return key; }
public V getValue() { return value; }
方法V setValue(V value)
如果参数null返回否则替换旧的value返回旧的value
方法boolean equals(Object 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(); }
// Types of Enumerations/Iterations private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2;
内部类 class Enumerator
内部类成员变量
final Entry,?>[] table = Hashtable.this.table; int index = table.length; Entry,?> entry; Entry,?> lastReturned; final int type; final boolean iterator;//指示此枚举器是用作迭代器还是枚举。 (true - > Iterator)。 protected int expectedModCount = Hashtable.this.modCount;//迭代器认为支持Hashtable应具有的modCount值。 如果违反了此期望,则迭代器已检测到并发修改。
常规构造函数Enumerator(int type, boolean iterator)
方法boolean hasMoreElements()
看当前桶和前面的桶内有没有元素,有元素则把entry和index都改成有元素的桶,返回true;都没有元素返回false;index初始值是桶的数量,所以相当于遍历了全部桶
方法 T nextElement()
从后往前找到第一个不为空的桶,如果type是key,返回桶内第一个元素的key,如果type是value,返回第一个元素的value,否则返回第一个元素;entry指向桶内第二个元素,lastReturn指向桶内第一个元素
方法boolean hasNext() { return hasMoreElements(); }
方法T next()
判断modcount后返回nextElement();
方法void remove()
不是迭代器抛异常,lastReturn为null抛异常,modcount不对抛异常;
同步的代码块synchronized(Hashtable.this) : 根据lastReturn的hash计算桶号,线性遍历桶内,移除lastReturn