java hashtable(1)

依然是先上翻译

这个类实现了从键映射到值的哈希表。任何非null的对象都可以成为键或者是值。
为了在哈希表中成功的存入和取出对象,作为key的对象必须实现hashcode方法和equals方法

一个哈希表的实例的性能被两个因素影响:初始容量和加载因子。容量是哈希表中桶的数量,初始容量就是哈希表创建时候的容量。哈希表是开放的,当遇到哈希冲撞的时候,一个桶会装着多个项,这些项必须被顺序的搜索。加载因子表示哈希表内装了百分之多少会自动增长容量。初始容量和负载系数参数仅仅是实现的提示。 关于何时以及是否调用rehash方法的确切细节是依赖于实现的。

通常来说,默认的加载因子0.75提供了空间和时间上的平衡。更高的值降低了空间的开销但提高了查找项的时间开销。

初始容量控制了浪费空间和非常浪费时间的重新哈希的平衡。如果哈希表的初始大小大于最大数目除以加载因子,则不会发生重新哈希操作。然而,把初始容量设的太高会浪费空间

如果很多的项会被放到哈希表中,创造时设定充分大的容量会让项插入时更加高效,而不是让容量自动的重新哈希并增长

基本都跟hashmap差不多,直接上最后一段最重要的
hashtable是同步的,如果不需要线程安全的实现,推荐使用hashmap而不是hashtable,如果需要线程安全高并发的实现,推荐使用concurrenthashmap

下面是代码辣

 

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

 

成员变量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<K> keys() { return this.<K>getEnumeration(KEYS); }

返回此哈希表中键的枚举。 在返回的对象上使用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}格式的字符串

 

方法<T> Enumeration<T> getEnumeration(int type)

如果没有元素,返回 Collections.emptyEnumeration();;否则返回new Enumerator<>(type, false);(后面会讲到这个内部类)

 

方法<T> Iterator<T> getIterator(int type)

同上,只是没有元素时返回的是Collections.emptyIterator();

 

成员变量

private transient volatile Set<K> keySet;

private transient volatile Set<Map.Entry<K,V>> entrySet;

private transient volatile Collection<V> values;

注释初始化每个字段以在第一次请求此视图时包含相应视图的实例。 视图是无状态的,因此没有理由创建多个视图。

 

核心方法Set<K> keySet()

如果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<K>

内部类中的常规方法

public Iterator<K> iterator() { return getIterator(KEYS); }

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<Map.Entry<K,V>> entrySet()

如果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<Map.Entry<K,V>>

常规方法

public Iterator<Map.Entry<K,V>> iterator() { return getIterator(ENTRIES); }

public boolean add(Map.Entry<K,V> o) { return super.add(o); }

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<V> values()

判断values是否为null,如果是null,赋值为Collections.synchronizedCollection(new ValueCollection(), this);;返回values

 

内部类class ValueCollection extends AbstractCollection<V>

常规方法

public Iterator<V> iterator() { return getIterator(VALUES); }

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<K,V> implements Map.Entry<K,V>

内部类成员变量

final int hash;
final K key;
V value;
Entry<K,V> next;

常规构造函数

方法Object clone() { return new Entry<>(hash, key, value, (next==null ? null : (Entry<K,V>) next.clone())); }

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<T> implements Enumeration<T>, Iterator<T>

内部类成员变量

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

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值