前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HashMap和HashTable的区别和联系

HashMap和HashTable的区别和联系

作者头像
IT云清
发布2019-01-22 10:17:21
3K0
发布2019-01-22 10:17:21
举报
文章被收录于专栏:IT云清IT云清

1.概览

父类

安全

是否可以null键null值

HashMap

AbstractMap

不安全

允许null值和null键

HashTable

Dictionary

安全

不允许null这null键

2.详情

2.1HashMap和HashTable的父类

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

代码语言:javascript
复制
public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable{}
代码语言:javascript
复制
public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {}

2.2二者的安全性问题

首先,要明白什么叫线程安全和线程不安全

线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问某个数据时,进行加锁保护,其他线程不能进行访问,直到该线程任务结束,其他线程才可使用。不会出现数据不一致或者数据污染。

 线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据,造成所得到的数据是脏数据。

而synchronized关键字,可以给方法或者代码块加锁,实现同步,此时,遇到多线程访问时,数据就是安全的。看HashTable的源码可知,HashTable的方法,都是synchronized同步的,所以,HashTable是同步的,安全的。而HashMap中,所有的方法,均没有加锁,所以,HashMap是不安全的。部分源码如下:

HashTable部分源码:

代码语言:javascript
复制
 public synchronized V get(Object key) {
        Entry tab[] = table;
        int hash = hash(key);
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<K,V> 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<? extends K, ? extends V> t) {
        for (Map.Entry<? extends K, ? extends V> 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部分源码:

代码语言:javascript
复制
 public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry<K,V> 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<K,V> 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)上面的注解如下:

代码语言:javascript
复制
   /**
     * Maps the specified <code>key</code> to the specified
     * <code>value</code> in this dictionary. Neither the key nor the
     * value can be <code>null</code>.
     * <p>
     * If this dictionary already contains an entry for the specified
     * <tt>key</tt>, the value already in this dictionary for that
     * <tt>key</tt> is returned, after modifying the entry to contain the
     *  new element. <p>If this dictionary does not already have an entry
     *  for the specified <tt>key</tt>, an entry is created for the
     *  specified <tt>key</tt> and <tt>value</tt>, and <tt>null</tt> is
     *  returned.
     * <p>
     * The <code>value</code> can be retrieved by calling the
     * <code>get</code> method with a <code>key</code> that is equal to
     * the original <code>key</code>.
     *
     * @param      key     the hashtable key.
     * @param      value   the value.
     * @return     the previous value to which the <code>key</code> was mapped
     *             in this dictionary, or <code>null</code> if the key did not
     *             have a previous mapping.
     * @exception  NullPointerException  if the <code>key</code> or
     *               <code>value</code> is <code>null</code>.
     * @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的源码,他自己也有这么一句:

代码语言:javascript
复制
* This class implements a hash table, which maps keys to values. Any
 * non-<code>null</code> object can be used as a key or as a value. <p>

另外,这个Dictory顶部注解还说:

代码语言:javascript
复制
 * The <code>Dictionary</code> class is the abstract parent of any
 * class, such as <code>Hashtable</code>, which maps keys to values.
 * Every key and every value is an object. In any one <tt>Dictionary</tt>
 * object, every key is associated with at most one value. Given a
 * <tt>Dictionary</tt> and a key, the associated element can be looked up.
 * Any non-<code>null</code> object can be used as a key and as a value.
 * <p>
 * As a rule, the <code>equals</code> method should be used by
 * implementations of this class to decide if two keys are the same.
 * <p>
 * <strong>NOTE: This class is obsolete.  New implementations should
 * implement the Map interface, rather than extending this class.</strong>
 *

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

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

而HashMap的源码中:

代码语言:javascript
复制
/**
     * 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 <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    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<K,V> 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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年09月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.概览
  • 2.详情
    • 2.1HashMap和HashTable的父类
      • 2.2二者的安全性问题
        • 2.3可否null键null值
          • 2.4关于HashTable安全的问题
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档