JAVA集合框架之Map接口实现类

java.util.HashMap<K,V>

基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。
HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。
如果很多映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。

构造方法

方法名 说明
HashMap() 构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap
HashMap(int initialCapacity) 构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap
HashMap(int initialCapacity, float loadFactor) 构造一个带指定初始容量和加载因子的空 HashMap
HashMap(Map<? extends K, ? extends V> m) 构造一个映射关系与指定 Map 相同的新 HashMap

方法摘要

返回值 方法名 说明
void clear() 从此映射中移除所有映射关系
Object clone() 返回此 HashMap 实例的浅表副本:并不复制键和值本身
boolean containsKey(Object key) 如果此映射包含对于指定键的映射关系,则返回 true
boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true
Set<Map.Entry<K,V>> entrySet() 返回此映射所包含的映射关系的 Set 视图
V get(Object key) 返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null
boolean isEmpty() 如果此映射不包含键-值映射关系,则返回 true
Set<K> keySet() 返回此映射中所包含的键的 Set 视图
V put(K key, V value) 在此映射中关联指定值与指定键
void putAll(Map<? extends K,? extends V> m) 将指定映射的所有映射关系复制到此映射中,这些映射关系将替换此映射目前针对指定映射中所有键的所有映射关系
V remove(Object key) 从此映射中移除指定键的映射关系(如果存在)
int size() 返回此映射中的键-值映射关系数
Collection<V> values() 返回此映射所包含的值的 Collection 视图

使用示例

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

public class HashMapDemo
{
   public static void main(String[] args)
   {
      HashMap<String, String> map = new HashMap<String, String>();
      // 向集合中添加数据
      for (int i = 0; i < 10; i++)
      {
         map.put("key" + i, "value" + i);
      }
      // 判断是否包含指定键
      System.out.println(map.containsKey("key1"));
      // 集合中元素个数
      System.out.println(map.size());
      // 遍历集合,使用keySet
      Iterator<String> iterator1 = map.keySet().iterator();
      while (iterator1.hasNext())
      {
         String key = iterator1.next();
         System.out.println(key + "=" + map.get(key));
      }
      System.out.println("==============================================");
      // 遍历集合,使用entrySet
      Iterator<Entry<String, String>> iterator2 = map.entrySet().iterator();
      while (iterator2.hasNext())
      {
         Entry<String, String> entry = iterator2.next();
         System.out.println(entry.getKey() + "=" + entry.getValue());
      }
   }
}

由上面例子的运行结果我们可以看出,遍历HashMap中的元素时顺序不是恒定不变的。

java.util.Hashtable<K,V>

Hashtable实现一个哈希表,该哈希表将键映射到相应的值。任何非 null 对象都可以用作键或值。
Hashtable与HashMap的区别主要有以下几点:

  1. Hashtable是Dictionary的子类,HashMap是Map接口的一个实现类;
  2. Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。即是说,在多线程应用程序中,不用专门的操作就安全地可以使用Hashtable了;而对于HashMap,则需要额外的同步机制。但HashMap的同步问题可通过Collections的一个静态方法得到解决:Map Collections.synchronizedMap(Map m)这个方法返回一个同步的Map,这个Map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的。
  3. 在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。

构造方法

方法名 说明
Hashtable() 用默认的初始容量 (11) 和加载因子 (0.75) 构造一个新的空哈希表
Hashtable(int initialCapacity) 用指定初始容量和默认的加载因子 (0.75) 构造一个新的空哈希表
Hashtable(int initialCapacity, float loadFactor) 用指定初始容量和指定加载因子构造一个新的空哈希表
Hashtable(Map<? extends K, ? extends V> t) 构造一个与给定的 Map 具有相同映射关系的新哈希表

方法摘要

返回值 方法名 说明
void clear() 将此哈希表清空,使其不包含任何键。
Object clone() 创建此哈希表的浅表副本。
boolean contains(Object value) 测试此映射表中是否存在与指定值关联的键。
boolean containsKey(Object key) 测试指定对象是否为此哈希表中的键。
boolean containsValue(Object value) 如果此 Hashtable 将一个或多个键映射到此值,则返回 true。
Enumeration<V> elements() 返回此哈希表中的值的枚举。
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的键的 Set 视图。
boolean equals(Object o) 按照 Map 接口的定义,比较指定 Object 与此 Map 是否相等。
V get(Object key) 返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null. 更确切地讲,如果此映射包含满足 (key.equals(k)) 的从键 k 到值 v 的映射,则此方法返回 v;否则,返回 null。
int hashCode() 按照 Map 接口的定义,返回此 Map 的哈希码值。
boolean isEmpty() 测试此哈希表是否没有键映射到值。
Enumeration<K> keys() 返回此哈希表中的键的枚举。
Set<K> keySet() 返回此映射中包含的键的 Set 视图。
V put(K key, V value) 将指定 key 映射到此哈希表中的指定 value。
void putAll(Map<? extends K,? extends V> t) 将指定映射的所有映射关系复制到此哈希表中,这些映射关系将替换此哈希表拥有的、针对当前指定映射中所有键的所有映射关系。
protected void rehash() 增加此哈希表的容量并在内部对其进行重组,以便更有效地容纳和访问其元素。
V remove(Object key) 从哈希表中移除该键及其相应的值。
int size() 返回此哈希表中的键的数量。
String toString() 返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 “, ” (逗号加空格)分隔开的、括在括号中的一组条目。
Collection<V> values() 返回此映射中包含的键的 Collection 视图

使用示例

Hashtable与HashMap使用方式类似,这里就不写例子了。

java.util.LinkedHashMap<K,V>

Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。注意,如果在映射中重新插入键,则插入顺序不受影响。(如果在调用 m.put(k, v) 前 m.containsKey(k) 返回了 true,则调用时会将键 k 重新插入到映射 m 中。)
此实现可以让客户避免未指定的、由 HashMap(及 Hashtable)所提供的通常为杂乱无章的排序工作,同时无需增加与 TreeMap 相关的成本。

构造方法

方法名 说明
LinkedHashMap() 构造一个带默认初始容量 (16) 和加载因子 (0.75) 的空插入顺序LinkedHashMap 实例
LinkedHashMap(int initialCapacity) 构造一个带指定初始容量和默认加载因子 (0.75) 的空插入顺序LinkedHashMap 实例
LinkedHashMap(int initialCapacity, float loadFactor) 构造一个带指定初始容量和加载因子的空插入顺序 LinkedHashMap 实例
LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) 构造一个带指定初始容量、加载因子和排序模式的空 LinkedHashMap 实例
LinkedHashMap(Map<<? extends K, ? extends V> m) 构造一个映射关系与指定映射相同的插入顺序 LinkedHashMap 实例

方法摘要

返回值 方法名 说明
void clear() 从该映射中移除所有映射关系
boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true
V get(Object key) 返回此映射到指定键的值
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) 如果此映射移除其最旧的条目,则返回 true

使用示例

LinkedHashMap继承自HashMap,所以LinkedHashMap具有HashMap的所有功能,可直接将HashMap例子中的类名替换为LinkedHashMap,运行后注意观察遍历集合的结果,这也是LinkedHashMap与HashMap最大的不同。遍历LinkedHashMap中的元素时,元素顺序与元素添加顺序相同。

java.util.TreeMap<K,V>

基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

构造方法

方法名 说明
TreeMap() 使用键的自然顺序构造一个新的、空的树映射
TreeMap(Comparator<? super K> comparator) 构造一个新的、空的树映射,该映射根据给定比较器进行排序
TreeMap(Map<? extends K,? extends V> m) 构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序 进行排序
TreeMap(SortedMap<K,? extends V> m) 构造一个与指定有序映射具有相同映射关系和相同排序顺序的新的树映射

方法摘要

返回值 方法名 说明
Map.Entry<K,V> ceilingEntry(K key) 返回一个键-值映射关系,它与大于等于给定键的最小键关联;如果不存在这样的键,则返回 null
K ceilingKey(K key) 返回大于等于给定键的最小键;如果不存在这样的键,则返回 null
void clear() 从此映射中移除所有映射关系
Object clone() 返回此 TreeMap 实例的浅表副本
Comparator<? super K> comparator() 返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回 null
boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回 true
boolean containsValue(Object value) 如果此映射为指定值映射一个或多个键,则返回 true
NavigableSet<K> descendingKeySet() 返回此映射中所包含键的逆序 NavigableSet 视图
NavigableMap<K,V> descendingMap() 返回此映射中所包含映射关系的逆序视图
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的 Set 视图
Map.Entry<K,V> firstEntry() 返回一个与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null
K firstKey() 返回此映射中当前第一个(最低)键
Map.Entry<K,V> floorEntry(K key) 返回一个键-值映射关系,它与小于等于给定键的最大键关联;如果不存在这样的键,则返回 null
K floorKey(K key) 返回小于等于给定键的最大键;如果不存在这样的键,则返回 null
V get(Object key) 返回指定键所映射的值,如果对于该键而言,此映射不包含任何映射关系,则返回 null
SortedMap<K,V> headMap(K toKey) 返回此映射的部分视图,其键值严格小于 toKey
NavigableMap<K,V> headMap(K toKey, boolean inclusive) 返回此映射的部分视图,其键小于(或等于,如果 inclusive 为 true)toKey
Map.Entry<K,V> higherEntry(K key) 返回一个键-值映射关系,它与严格大于给定键的最小键关联;如果不存在这样的键,则返回 null
K higherKey(K key) 返回严格大于给定键的最小键;如果不存在这样的键,则返回 null
Set<K> keySet() 返回此映射包含的键的 Set 视图
Map.Entry<K,V> lastEntry() 返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null
K lastKey() 返回映射中当前最后一个(最高)键
Map.Entry<K,V> lowerEntry(K key) 返回一个键-值映射关系,它与严格小于给定键的最大键关联;如果不存在这样的键,则返回 null
K lowerKey(K key) 返回严格小于给定键的最大键;如果不存在这样的键,则返回 null
NavigableSet<K> navigableKeySet() 返回此映射中所包含键的 NavigableSet 视图
Map.Entry<K,V> pollFirstEntry() 移除并返回与此映射中的最小键关联的键-值映射关系;如果映射为空,则返回 null
Map.Entry<K,V> pollLastEntry() 移除并返回与此映射中的最大键关联的键-值映射关系;如果映射为空,则返回 null
V put(K key, V value) 将指定值与此映射中的指定键进行关联
void putAll(Map<? extends K,? extends V> map) 将指定映射中的所有映射关系复制到此映射中
V remove(Object key) 如果此 TreeMap 中存在该键的映射关系,则将其删除
int size() 返回此映射中的键-值映射关系数
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) 返回此映射的部分视图,其键的范围从 fromKey 到 toKey
SortedMap<K,V> subMap(K fromKey, K toKey) 返回此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)
SortedMap<K,V> tailMap(K fromKey) 返回此映射的部分视图,其键大于等于 fromKey
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) 返回此映射的部分视图,其键大于(或等于,如果 inclusive 为 true)fromKey
Collection<V> values() 返回此映射包含的值的 Collection 视图

使用示例

TreeMap与HashMap的用法也基本相同,不同之处也是元素的顺序。

java.util.Properties

Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
一个属性列表可包含另一个属性列表作为它的“默认值”;如果未能在原有的属性列表中搜索到属性键,则搜索第二个属性列表。
因为 Properties 继承于 Hashtable,所以可对 Properties 对象应用 put 和 putAll 方法。但不建议使用这两个方法,因为它们允许调用者插入其键或值不是 String 的项。相反,应该使用 setProperty 方法。如果在“不安全”的 Properties 对象(即包含非 String 的键或值)上调用 store 或 save 方法,则该调用将失败。类似地,如果在“不安全”的 Properties 对象(即包含非 String 的键)上调用propertyNames 或 list 方法,则该调用将失败。

构造方法

方法名 说明
Properties() 创建一个无默认值的空属性列表
Properties(Properties defaults) 创建一个带有指定默认值的空属性列表

方法摘要

返回值 方法名 说明
String getProperty(String key) 用指定的键在此属性列表中搜索属性
String getProperty(String key, String defaultValue) 用指定的键在属性列表中搜索属性
void list(PrintStream out) 将属性列表输出到指定的输出流
void list(PrintWriter out) 将属性列表输出到指定的输出流
void load(InputStream inStream) 从输入流中读取属性列表(键和元素对)
void load(Reader reader) 按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)
void loadFromXML(InputStream in) 将指定输入流中由 XML 文档所表示的所有属性加载到此属性表中
Enumeration<?> propertyNames() 返回属性列表中所有键的枚举,如果在主属性列表中未找到同名的键,则包括默认属性列表中不同的键
void save(OutputStream out, String comments) 已过时如果在保存属性列表时发生 I/O 错误,则此方法不抛出 IOException保存属性列表的首选方法是通过 store(OutputStream out, String comments) 方法或 storeToXML(OutputStream os, String comment) 方法来进行
Object setProperty(String key, String value) 调用 Hashtable 的方法 put
void store(OutputStream out, String comments) 以适合使用 load(InputStream) 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流
void store(Writer writer, String comments) 以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符
void storeToXML(OutputStream os, String comment) 发出一个表示此表中包含的所有属性的 XML 文档
void storeToXML(OutputStream os, String comment, String encoding) 使用指定的编码发出一个表示此表中包含的所有属性的 XML 文档
Set<String> stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键

使用示例

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDemo
{
   public static void main(String[] args)
   {
      Properties properties = new Properties();
      // 向集合中添加数据
      for (int i = 0; i < 10; i++)
      {
         properties.setProperty("key" + i, "value" + i);
      }
      // 将集合持久化到资源文件中,对应的读取使用load方法
      FileOutputStream out = null;
      try
      {
         out = new FileOutputStream("PropertiesDemo.properties");
         properties.store(out, "PropertiesDemo");
      }
      catch (IOException e)
      {
         e.printStackTrace();
      }
      finally
      {
         if (out != null)
         {
            try
            {
               out.close();
            }
            catch (IOException e)
            {
            }
         }
      }
   }
}

打开持久化文件的查看内容(文本)如下:
#PropertiesDemo
#Tue Dec 29 09:44:52 CST 2015
key9=value9
key8=value8
key7=value7
key6=value6
key5=value5
key4=value4
key3=value3
key2=value2
key1=value1
key0=value0

上述例子中,只介绍了如何将Properties持久化到properties文件中,Properties还可以直接持久化到XML中,大家可以自己试一下。

上一篇:iOS中动态更新补丁策略JSPatch运用基础二


下一篇:JavaScript之对象赋值(浅谈一道面试题)