HashMap和HashTable的区别和联系
发布日期:2021-06-30 11:04:09 浏览次数:2 分类:技术文章

本文共 6363 字,大约阅读时间需要 21 分钟。

1.概览

父类 安全 是否可以null键null值
HashMap AbstractMap
不安全 允许null值和null键
HashTable Dictionary
安全 不允许null这null键  

2.详情

2.1HashMap和HashTable的父类

看两个类的源码就可以知道:

public class HashMap
extends AbstractMap
implements Map
, Cloneable, Serializable{}

public class Hashtable
extends 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 (Entry
e = 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();        Entry
entry = 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 key to the specified     * value in this dictionary. Neither the key nor the     * value can be null.     * 

* 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 a key that is equal to * the original key. * * @param key the hashtable key. * @param value the value. * @return the previous value to which the key was mapped * in this dictionary, or null if the key did not * have a previous mapping. * @exception NullPointerException if the key or * value is null. * @see java.lang.Object#equals(java.lang.Object) * @see java.util.Dictionary#get(java.lang.Object) */ abstract public V put(K key, V value);

而且,还说
NullPointerException  if the <code>key</code> or
 <code>value</code> is <code>null</code>,当key或者value为null时,会抛出
NullPointerException 。

父类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 Dictionary class is the abstract parent of any * class, such as Hashtable, 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. *

这是HashTable这样键值对类的父类,.........这个类过时了,新的实现者,应该去实现Map接口,而不是这个。

----------------------------------------

而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 (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; }

源码中未对key和value做任何限制,而且方法中,key是null,那就放putForNullKey好了,根本不管这个。

所以,HashTable不允许null key or null value,而HashMap可以。

2.4关于HashTable安全的问题

笔者多年前,面试中,被问到这个问题,说完两个集合的安全问题后,面试官问我,HashTable的同步锁是加在哪里?有什么区别?显然,如果没有看过源码,是不能确定这个synchronized是加在哪里的。
HashTable的synchronized,锁是加在方法上的。加在不同的地方,区别是锁对象不同:
同步代码块:任意对象
同步方法:this
静态同步方法:类名.class

转载地址:https://it4all.blog.csdn.net/article/details/78055488 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SQL---DATE_ADD()函数
下一篇:HashMap的底层原理及源码分析

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月05日 16时03分41秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

Python反射机制 2019-04-30
YAPF —— Python代码格式化工具 2019-04-30
MMOCR——config文件 2019-04-30
NCCL 2019-04-30
pip install git+ 2019-04-30
UGC 用户产生内容 2019-04-30
ranger 2019-04-30
slurm 2019-04-30
xfce4 2019-04-30
xrdp 2019-04-30
Raft算法 2019-04-30
Python计算文本BLEU分数 2019-04-30
swap内存(linux) 2019-04-30
人脸au 2019-04-30
torch.distributed 分布式 2019-04-30
OpenMP编程模型(OMP) 2019-04-30
混合精度训练(FP16 & FP32) 2019-04-30
PyPy 2019-04-30
打印CSDN文章 2019-04-30
MATLAB与CUDA 2019-04-30