Java学习笔记(34)——Java集合06之HashTable

一、概述

Hashtable 简介

HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射
Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。

Hashtable 的实例有两个参数影响其性能:初始容量加载因子。容量 是哈希表中桶 的数量,初始容量 就是哈希表创建时的容量。注意,哈希表的状态为 open:在发生“哈希冲突”的情况下,单个桶会存储多个条目,这些条目必须按顺序搜索。加载因子 是对哈希表在其容量自动增加之前可以达到多满的一个尺度。初始容量和加载因子这两个参数只是对该实现的提示。关于何时以及是否调用 rehash 方法的具体细节则依赖于该实现。
通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间(在大多数 Hashtable 操作中,包括 get 和 put 操作,都反映了这一点)。

Hashtable的构造函数

// 默认构造函数。
public Hashtable() 

// 指定“容量大小”的构造函数
public Hashtable(int initialCapacity) 

// 指定“容量大小”和“加载因子”的构造函数
public Hashtable(int initialCapacity, float loadFactor) 

// 包含“子Map”的构造函数
public Hashtable(Map<? extends K, ? extends V> t)

Hashtable的API

synchronized void                clear()
synchronized Object              clone()
             boolean             contains(Object value)
synchronized boolean             containsKey(Object key)
synchronized boolean             containsValue(Object value)
synchronized Enumeration<V>      elements()
synchronized Set<Entry<K, V>>    entrySet()
synchronized boolean             equals(Object object)
synchronized V                   get(Object key)
synchronized int                 hashCode()
synchronized boolean             isEmpty()
synchronized Set<K>              keySet()
synchronized Enumeration<K>      keys()
synchronized V                   put(K key, V value)
synchronized void                putAll(Map<? extends K, ? extends V> map)
synchronized V                   remove(Object key)
synchronized int                 size()
synchronized String              toString()
synchronized Collection<V>       values()

二、HashTable数据结构

  Hashtable的继承关系

java.lang.Object
   ↳     java.util.Dictionary<K, V>
         ↳     java.util.Hashtable<K, V>public class Hashtable<K,V> extends Dictionary<K,V>    implements Map<K,V>, Cloneable, java.io.Serializable { }

Hashtable与Map关系如下图:

从图中可以看出:
(01) Hashtable继承于Dictionary类,实现了Map接口。Map是"key-value键值对"接口,Dictionary是声明了操作"键值对"函数接口的抽象类。
(02) Hashtable是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, count, threshold, loadFactor, modCount
  table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。
  count是Hashtable的大小,它是Hashtable保存的键值对的数量。
  threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值="容量*加载因子"。
  loadFactor就是加载因子。
  modCount是用来实现fail-fast机制的

三、HashTable遍历方式

3.1 遍历Hashtable的键值对

第一步:根据entrySet()获取Hashtable的“键值对”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设table是Hashtable对象
// table中的key是String类型,value是Integer类型
Integer integ = null;
Iterator iter = table.entrySet().iterator();
while(iter.hasNext()) {
    Map.Entry entry = (Map.Entry)iter.next();
    // 获取key
    key = (String)entry.getKey();
        // 获取value
    integ = (Integer)entry.getValue();
}

3.2 通过Iterator遍历Hashtable的键

第一步:根据keySet()获取Hashtable的“键”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设table是Hashtable对象
// table中的key是String类型,value是Integer类型
String key = null;
Integer integ = null;
Iterator iter = table.keySet().iterator();
while (iter.hasNext()) {
        // 获取key
    key = (String)iter.next();
        // 根据key,获取value
    integ = (Integer)table.get(key);
}

3.3 通过Iterator遍历Hashtable的值

第一步:根据value()获取Hashtable的“值”的集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设table是Hashtable对象
// table中的key是String类型,value是Integer类型
Integer value = null;
Collection c = table.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

3.4 通过Enumeration遍历Hashtable的键

第一步:根据keys()获取Hashtable的集合。
第二步:通过Enumeration遍历“第一步”得到的集合。

Enumeration enu = table.keys();
while(enu.hasMoreElements()) {
    System.out.println(enu.nextElement());
}

3.5 通过Enumeration遍历Hashtable的值

第一步:根据elements()获取Hashtable的集合。
第二步:通过Enumeration遍历“第一步”得到的集合。

Enumeration enu = table.elements();
while(enu.hasMoreElements()) {
    System.out.println(enu.nextElement());
}

遍历测试程序如下

import java.util.*;

/*
 * @desc 遍历Hashtable的测试程序。
 *   (01) 通过entrySet()去遍历key、value,参考实现函数:
 *        iteratorHashtableByEntryset()
 *   (02) 通过keySet()去遍历key,参考实现函数:
 *        iteratorHashtableByKeyset()
 *   (03) 通过values()去遍历value,参考实现函数:
 *        iteratorHashtableJustValues()
 *   (04) 通过Enumeration去遍历key,参考实现函数:
 *        enumHashtableKey()
 *   (05) 通过Enumeration去遍历value,参考实现函数:
 *        enumHashtableValue()
 *
 * @author skywang
 */
public class HashtableIteratorTest {

    public static void main(String[] args) {
        int val = 0;
        String key = null;
        Integer value = null;
        Random r = new Random();
        Hashtable table = new Hashtable();

        for (int i=0; i<12; i++) {
            // 随机获取一个[0,100)之间的数字
            val = r.nextInt(100);
            
            key = String.valueOf(val);
            value = r.nextInt(5);
            // 添加到Hashtable中
            table.put(key, value);
            System.out.println(" key:"+key+" value:"+value);
        }
        // 通过entrySet()遍历Hashtable的key-value
        iteratorHashtableByEntryset(table) ;
        
        // 通过keySet()遍历Hashtable的key-value
        iteratorHashtableByKeyset(table) ;
        
        // 单单遍历Hashtable的value
        iteratorHashtableJustValues(table);        

        // 遍历Hashtable的Enumeration的key
        enumHashtableKey(table);

        // 遍历Hashtable的Enumeration的value
        //enumHashtableValue(table);
    }
            
    /*
     * 通过Enumeration遍历Hashtable的key
     * 效率高!
     */
    private static void enumHashtableKey(Hashtable table) {
        if (table == null)
            return ;

        System.out.println("\nenumeration Hashtable");
        Enumeration enu = table.keys();
        while(enu.hasMoreElements()) {
            System.out.println(enu.nextElement());
        }
    }

    
    /*
     * 通过Enumeration遍历Hashtable的value
     * 效率高!
     */
    private static void enumHashtableValue(Hashtable table) {
        if (table == null)
            return ;

        System.out.println("\nenumeration Hashtable");
        Enumeration enu = table.elements();
        while(enu.hasMoreElements()) {
            System.out.println(enu.nextElement());
        }
    }

    /*
     * 通过entry set遍历Hashtable
     * 效率高!
     */
    private static void iteratorHashtableByEntryset(Hashtable table) {
        if (table == null)
            return ;

        System.out.println("\niterator Hashtable By entryset");
        String key = null;
        Integer integ = null;
        Iterator iter = table.entrySet().iterator();
        while(iter.hasNext()) {
            Map.Entry entry = (Map.Entry)iter.next();
            
            key = (String)entry.getKey();
            integ = (Integer)entry.getValue();
            System.out.println(key+" -- "+integ.intValue());
        }
    }

    /*
     * 通过keyset来遍历Hashtable
     * 效率低!
     */
    private static void iteratorHashtableByKeyset(Hashtable table) {
        if (table == null)
            return ;

        System.out.println("\niterator Hashtable By keyset");
        String key = null;
        Integer integ = null;
        Iterator iter = table.keySet().iterator();
        while (iter.hasNext()) {
            key = (String)iter.next();
            integ = (Integer)table.get(key);
            System.out.println(key+" -- "+integ.intValue());
        }
    }
    

    /*
     * 遍历Hashtable的values
     */
    private static void iteratorHashtableJustValues(Hashtable table) {
        if (table == null)
            return ;
        
        Collection c = table.values();
        Iterator iter= c.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());
       }
    }
}

四、HashTable与HashMap的区别

HashTable和HashMap存在很多的相同点,但是他们还是有几个比较重要的不同点。

      第一:我们从他们的定义就可以看出他们的不同,HashTable基于Dictionary类,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可将键映射到相应值的类的抽象父类,而AbstractMap是基于Map接口的骨干实现,它以最大限度地减少实现此接口所需的工作。

      第二:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。如下:

      当HashMap遇到为null的key时,它会调用putForNullKey方法来进行处理。对于value没有进行任何处理,只要是对象都可以。

if (key == null)            return putForNullKey(value);

      而当HashTable遇到null时,他会直接抛出NullPointerException异常信息。

if (value == null) 
{            
  throw new NullPointerException();
}

      第三:Hashtable的方法是同步的,而HashMap的方法不是。所以有人一般都建议如果是涉及到多线程同步时采用HashTable,没有涉及就采用HashMap,但是在Collections类中存在一个静态方法:synchronizedMap(),该方法创建了一个线程安全的Map对象,并把它作为一个封装的对象来返回,所以通过Collections类的synchronizedMap方法是可以我们你同步访问潜在的HashMap。

转载于:https://my.oschina.net/jewill/blog/411806

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值