HashMap,HashTable

HashMap

概述

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

HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

数据结构

这里写图片描述

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

fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件(http://www.cnblogs.com/skywang12345/p/3308762.html)

HashMap的构造函数

HashMap共有4个构造函数

// 默认构造函数。
HashMap()

// 指定“容量大小”的构造函数
HashMap(int capacity)

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

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

HashMap的API

void                 clear()
Object               clone()
boolean              containsKey(Object key)
boolean              containsValue(Object value)
Set<Entry<K, V>>     entrySet()
V                    get(Object key)
boolean              isEmpty()
Set<K>               keySet()
V                    put(K key, V value)
void                 putAll(Map<? extends K, ? extends V> map)
V                    remove(Object key)
int                  size()
Collection<V>        values()

HashMap源码解析

http://www.cnblogs.com/skywang12345/p/3310835.html

HashMap的遍历

遍历HashMap的键值对

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

推荐的遍历方式:

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

遍历HashMap的键

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

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

遍历HashMap的值

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

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

HashMap示例

public class Test {
     public static void main(String[] args) {
            testHashMapAPIs();
        }

        private static void testHashMapAPIs() {
            // 初始化随机种子
            Random r = new Random();
            // 新建HashMap
            HashMap<String,Integer> map = new HashMap<String,Integer>();
            // 添加操作
            map.put("one", r.nextInt(10));
            map.put("two", r.nextInt(10));
            map.put("three", r.nextInt(10));

            // 打印出map
            System.out.println("map:"+map );

            // 通过Iterator遍历key-value
            Iterator iter = map.entrySet().iterator();
            while(iter.hasNext()) {
                Map.Entry entry = (Map.Entry)iter.next();
                System.out.println("next : "+ entry.getKey() +" - "+entry.getValue());
            }

            // HashMap的键值对个数        
            System.out.println("size:"+map.size());

            // containsKey(Object key) :是否包含键key
            System.out.println("contains key two : "+map.containsKey("two"));
            System.out.println("contains key five : "+map.containsKey("five"));

            // containsValue(Object value) :是否包含值value
            System.out.println("contains value 0 : "+map.containsValue(Integer.valueOf(0)));

            // remove(Object key) : 删除键key对应的键值对
            map.remove("three");

            System.out.println("map:"+map );

            // clear() : 清空HashMap
            map.clear();

            // isEmpty() : HashMap是否为空
            System.out.println((map.isEmpty()?"map is empty":"map is not empty") );
        }
}

输出:

map:{two=6, one=5, three=5}

two : 6

one : 5

three : 5

size:3

contains key two : true

contains key five : false

contains value 0 : false

map:{two=6, one=5}

map is empty

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数据结构

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的构造函数

// 默认构造函数。
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源码解析(基于JDK1.6.0_45)

http://www.cnblogs.com/skywang12345/p/3310887.html

Hashtable遍历方式

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

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);
}

4.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();
}

4.4 通过Enumeration遍历Hashtable的键

第一步:根据keys()获取Hashtable的集合。

第二步:通过Enumeration遍历“第一步”得到的集合。

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

4.5 通过Enumeration遍历Hashtable的值

第一步:根据elements()获取Hashtable的集合。

第二步:通过Enumeration遍历“第一步”得到的集合。

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

Hashtable示例

public class Test {
    public static void main(String[] args) {
        testHashtableAPIs();
    }

    private static void testHashtableAPIs() {
        // 初始化随机种子
        Random r = new Random();
        // 新建Hashtable
        Hashtable table = new Hashtable();
        // 添加操作
        table.put("one", r.nextInt(10));
        table.put("two", r.nextInt(10));
        table.put("three", r.nextInt(10));

        // 打印出table
        System.out.println("table:"+table );

        // 通过Iterator遍历key-value
        Iterator iter = table.entrySet().iterator();
        while(iter.hasNext()) {
            Map.Entry entry = (Map.Entry)iter.next();
            System.out.println( entry.getKey() +" : "+entry.getValue());
        }

        // Hashtable的键值对个数        
        System.out.println("size:"+table.size());

        // containsKey(Object key) :是否包含键key
        System.out.println("contains key two : "+table.containsKey("two"));
        System.out.println("contains key five : "+table.containsKey("five"));

        // containsValue(Object value) :是否包含值value
        System.out.println("contains value 0 : "+table.containsValue(new Integer(0)));

        // remove(Object key) : 删除键key对应的键值对
        table.remove("three");

        System.out.println("table:"+table );

        // clear() : 清空Hashtable
        table.clear();

        // isEmpty() : Hashtable是否为空
        System.out.println((table.isEmpty()?"table is empty":"table is not empty") );
    }
}

输出: table:{two=5, one=6, three=9}

two : 5

one : 6

three : 9

size:3

contains key two : true

contains key five : false

contains value 0 : false

table:{two=5, one=6}

table is empty

results matching ""

    No results matching ""