本文共 6363 字,大约阅读时间需要 21 分钟。
1.概览
父类 | 安全 | 是否可以null键null值 | ||
HashMap | AbstractMap | 不安全 | 允许null值和null键 | |
HashTable | Dictionary | 安全 | 不允许null这null键 |
2.详情
2.1HashMap和HashTable的父类
看两个类的源码就可以知道:
public class HashMapextends AbstractMap implements Map , Cloneable, Serializable{}
public class Hashtableextends Dictionary implements Map , Cloneable, java.io.Serializable {}
2.2二者的安全性问题
首先,要明白什么叫线程安全和线程不安全
线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问某个数据时,进行加锁保护,其他线程不能进行访问,直到该线程任务结束,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据,造成所得到的数据是脏数据。
而synchronized关键字,可以给方法或者代码块加锁,实现同步,此时,遇到多线程访问时,数据就是安全的。看HashTable的源码可知,HashTable的方法,都是synchronized同步的,所以,HashTable是同步的,安全的。而HashMap中,所有的方法,均没有加锁,所以,HashMap是不安全的。部分源码如下:
HashTable部分源码:
public synchronized V get(Object key) { Entry tab[] = table; int hash = hash(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entrye = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { return e.value; } } return null; } public synchronized void putAll(Map t) { for (Map.Entry e : t.entrySet()) put(e.getKey(), e.getValue()); } /** * Clears this hashtable so that it contains no keys. */ public synchronized void clear() { Entry tab[] = table; modCount++; for (int index = tab.length; --index >= 0; ) tab[index] = null; count = 0; }
HashMap部分源码:
public V get(Object key) { if (key == null) return getForNullKey(); Entryentry = getEntry(key); return null == entry ? null : entry.getValue(); } public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entry e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
2.3可否null键null值
看源码,HashTable extends Dictionary<K,V>,这个Dictionary类,源码中:abstract public V put(K key, V value)上面的注解如下:
/** * Maps the specified而且,还说 NullPointerException if the <code>key</code> or <code>value</code> is <code>null</code>,当key或者value为null时,会抛出 NullPointerException 。key
to the specified *value
in this dictionary. Neither the key nor the * value can benull
. ** If this dictionary already contains an entry for the specified * key, the value already in this dictionary for that * key is returned, after modifying the entry to contain the * new element.
If this dictionary does not already have an entry * for the specified key, an entry is created for the * specified key and value, and null is * returned. *
* The
value
can be retrieved by calling the *get
method with akey
that is equal to * the originalkey
. * * @param key the hashtable key. * @param value the value. * @return the previous value to which thekey
was mapped * in this dictionary, ornull
if the key did not * have a previous mapping. * @exception NullPointerException if thekey
or *value
isnull
. * @see java.lang.Object#equals(java.lang.Object) * @see java.util.Dictionary#get(java.lang.Object) */ abstract public V put(K key, V value);
父类Dictionary的put()方法在这里说了:Neither the key nor the value can be <code>null</code>.key或者value,都不允许为空,那子类的put()方法,继承自父类,当然不允许null值和null键了;
另外,如果仔细看HashTable的源码,他自己也有这么一句:
* This class implements a hash table, which maps keys to values. Any * non-null
object can be used as a key or as a value.
另外,这个Dictory顶部注解还说:
* The这是HashTable这样键值对类的父类,.........这个类过时了,新的实现者,应该去实现Map接口,而不是这个。Dictionary
class is the abstract parent of any * class, such asHashtable
, which maps keys to values. * Every key and every value is an object. In any one Dictionary * object, every key is associated with at most one value. Given a * Dictionary and a key, the associated element can be looked up. * Any non-null
object can be used as a key and as a value. ** As a rule, the
equals
method should be used by * implementations of this class to decide if two keys are the same. ** NOTE: This class is obsolete. New implementations should * implement the Map interface, rather than extending this class. *
----------------------------------------
而HashMap的源码中:
/** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or * null if there was no mapping for key. * (A null return can also indicate that the map * previously associated null with key.) */ public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); for (Entrye = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
源码中未对key和value做任何限制,而且方法中,key是null,那就放putForNullKey好了,根本不管这个。
所以,HashTable不允许null key or null value,而HashMap可以。
2.4关于HashTable安全的问题
转载地址:https://it4all.blog.csdn.net/article/details/78055488 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!