`
salever
  • 浏览: 255664 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

闲聊HahMap与Hashtable

阅读更多

    在使用Map下面的集合时,很多时候都会遇到HashMap与Hashtable的选择,究竟哪一个更合适?相信很多资料都是这么讲它们的区别的:HashMap可以使用null作为key,而Hashtable则是线程安全的。

    笔者在面试的时候也会被问过的这个问题,有时候真的想不起来哪一个支持null key哪一个是线程安全的了。把这些东西作为概念性的知识记下来是一件很痛苦的事情,也是一件不明智的事情。究竟它们为什么有区别呢?看看源码就知道了。

    先看看HashMap,为什么支持null作为key值。

 public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        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;
    }

    这是HashMap的put()方法,在key为null时,会有一个putForNullKey()方法处理,这就明白了为什么它支持null key了。至于它怎么支持null key,不妨再看看putForNullKey()的实现:

 

   private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }

    同样,在get元素的时候,也会有对null key的单独处理:

 

 public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

    而Hashtable呢?

 

 public synchronized V put(K key, V value) {
	// Make sure the value is not null
	if (value == null) {
	    throw new NullPointerException();
	}

	// Makes sure the key is not already in the hashtable.
	Entry tab[] = table;
	int hash = key.hashCode();
	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)) {
		V old = e.value;
		e.value = value;
		return old;
	    }
	}

	modCount++;
	if (count >= threshold) {
	    // Rehash the table if the threshold is exceeded
	    rehash();

            tab = table;
            index = (hash & 0x7FFFFFFF) % tab.length;
	}

	// Creates the new entry.
	Entry<K,V> e = tab[index];
	tab[index] = new Entry<K,V>(hash, key, value, e);
	count++;
	return null;
    }

     抛出一个异常。到这就很清晰了,为什么一个支持一个不支持。而线程安全怎么说?接下来再看Hashtable中的一些方法:

 

   public synchronized V remove(Object key) {
	Entry tab[] = table;
	int hash = key.hashCode();
	int index = (hash & 0x7FFFFFFF) % tab.length;
	for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
	    if ((e.hash == hash) && e.key.equals(key)) {
		modCount++;
		if (prev != null) {
		    prev.next = e.next;
		} else {
		    tab[index] = e.next;
		}
		count--;
		V oldValue = e.value;
		e.value = null;
		return oldValue;
	    }
	}
	return null;
    }

    /**
     * Copies all of the mappings from the specified map to this hashtable.
     * These mappings will replace any mappings that this hashtable had for any
     * of the keys currently in the specified map.
     *
     * @param t mappings to be stored in this map
     * @throws NullPointerException if the specified map is null
     * @since 1.2
     */
    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());
    }

     它们都有关键字synchronized,给它的一些方法加上了锁,因此它是线程安全的。就这么简单。细心一点的还可以发现它们的在取值的时候有些不同:

    HashMap:

  public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

  static int indexFor(int h, int length) {
        return h & (length-1);
    }

    而Hashtable:

 public synchronized V get(Object key) {
	Entry tab[] = table;
	int hash = key.hashCode();
	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;
    }

    很明显,它们的对索引的处理也不一样。究竟好一个更好,还得再仔细分析下,下回见。

0
0
分享到:
评论

相关推荐

    hashmap与hashtable区别

    ### HashMap与Hashtable的区别 在Java编程语言中,`HashMap`和`Hashtable`是两种非常重要的数据结构,它们都用于存储键值对。然而,在实际应用过程中,这两种数据结构有着本质的不同,下面将详细介绍这些差异。 ##...

    HashMap与HashTable区别

    ### HashMap与HashTable的区别 在Java编程语言中,`HashMap`和`HashTable`是两种非常重要的数据结构,它们都实现了`Map`接口,并提供了键值对的存储方式。这两种数据结构虽然相似,但在实现细节和使用场景上存在...

    C# json 转hashtable

    与此相关的,`Hashtable`是.NET框架中的一个古老的集合类,用于存储键值对,它在早期的.NET应用中十分常见。然而,随着.NET Framework的发展,`Dictionary, TValue&gt;`逐渐取代了`Hashtable`,因为后者不支持泛型,且...

    HashMap与HashTable和HashSet的区别

    ### HashMap与HashTable和HashSet的区别 #### 一、概述 在Java集合框架中,`HashMap`, `HashTable` 和 `HashSet` 是三个重要的数据结构,它们分别实现了`Map`接口和`Set`接口,提供了不同的功能来满足不同的编程...

    WinFormHashTable最简单用法,.net hashtable ,hashtable ,hashtable用法

    在WinForm应用中,Hashtable常用于存储用户界面控件与数据之间的关联,或者在事件处理中暂存数据。例如,可以创建一个Hashtable来存储窗体控件与数据库字段的对应关系,方便数据绑定和操作。 5. **注意点** - **...

    HashMap与HashTable的区别(含源码分析)

    在Java编程语言中,`HashMap`和`HashTable`都是实现键值对存储的数据结构,但它们之间存在一些显著的区别,这些区别主要体现在线程安全性、性能、null值处理以及一些方法特性上。以下是对这两个类的详细分析: 1. ...

    HashMap和HashTable的区别和不同

    ### HashMap与HashTable的区别详解 #### 引言 在Java编程中,`HashMap`与`HashTable`作为两种常用的数据结构,经常被用来存储键值对数据。尽管它们在功能上相似,但在实现细节、性能表现以及使用场景方面存在显著...

    hashtable和dictionary的探讨

    在编程领域,哈希表(Hashtable)和字典(Dictionary)是两种常用的数据结构,它们在存储和检索键值对时提供了高效的性能。本文将深入探讨这两种数据结构的原理、性能差异以及实际应用中的考虑因素。 哈希表,通常...

    hashMap和hashTable的区别

    #### 一、简介与基本概念 `HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在实现细节和性能特性上存在显著差异...

    HashTable

    3. 插入与查找:插入操作首先计算键的哈希值,然后根据哈希值找到对应的位置进行插入。查找操作同样计算哈希值,找到对应位置后,如果是链地址法,则需要遍历链表查找匹配的键。 4. 删除:删除操作涉及到如何找到要...

    asp.net遍历hashtable

    在ASP.NET中,Hashtable是一种常用的数据结构,它是一个键值对集合,允许程序员存储和检索对象。本篇文章将深入探讨如何在ASP.NET中遍历Hashtable,以及相关的重要知识点。 首先,理解Hashtable的基本概念至关重要...

    hashtable序列化与反序列化

    本文将详细探讨标题所提及的“hashtable序列化与反序列化”,并提供一个基本的示例。 首先,让我们理解什么是序列化。序列化是将对象的状态转换为可存储或可传输的形式的过程。在Java中,对象序列化允许我们将一个...

    hashtable存储数据.rar

    在Java编程语言中,`Hashtable`是一个非常基础且重要的数据结构,它属于集合框架的一部分,提供了键值对(key-value pairs)的存储功能。`Hashtable`类是线程安全的,意味着在多线程环境下,它能确保数据的一致性和...

    HashMap和HashTable底层原理以及常见面试题

    HashMap和HashTable底层原理以及常见面试题 HashMap和HashTable是Java中两个常用的数据结构,都是基于哈希表实现的,但它们之间存在着一些关键的区别。本文将深入探讨HashMap和HashTable的底层原理,并总结常见的...

    C#-Hashtable应用

    除了基本操作,Hashtable还提供了其他有用的方法,如Clear()用于清除所有元素,CopyTo()用于将Hashtable复制到数组,以及GetHashCode()和Equals()方法,这些方法与对象的比较和身份验证有关。 在处理集合时,遍历是...

    java Hashtable的泛型化

    3. **自动装箱与拆箱**:对于基本类型对应的包装类,泛型`Hashtable`支持自动装箱(如`Integer`与`int`之间)和拆箱,简化了代码。 4. **可读性**:通过明确指定类型,代码的意图更加清晰,阅读和维护起来更容易。 ...

    经典讲解List和ArrayList和Vector和HashTable和HashMap区别

    `Vector`也是`List`接口的实现,与`ArrayList`类似,但它是线程安全的。这意味着在多线程环境下,多个线程可以同时操作`Vector`而不会产生数据不一致的问题。但是,由于其同步机制,性能通常低于`ArrayList`。 4. ...

    hashtable和hashmap的区别

    ### Hashtable和HashMap的区别 在Java编程语言中,`Hashtable`和`HashMap`是两种非常重要的数据结构,它们都实现了`Map`接口,用于存储键值对。尽管它们有着相似的功能,但在实现细节和应用场景上存在显著差异。接...

    C# .net HashTable

    在本文中,我们将深入探讨`HashTable`的各个方面,包括它的特点、使用方法、操作以及与其他数据结构的比较。 1. **哈希表基础** 哈希表是一种数据结构,通过计算键的哈希值并将其映射到特定位置来存储数据,以便...

    Hashtable的使用

    - **不允许`null`键和`null`值**:与`HashMap`不同,`Hashtable`不允许插入`null`键或`null`值。如果你尝试这样做,会抛出`NullPointerException`。 - **非有序性**:`Hashtable`中的元素顺序并不是按照插入的顺序...

Global site tag (gtag.js) - Google Analytics