Chinaunix首页 | 论坛 | 博客
  • 博客访问: 743365
  • 博文数量: 130
  • 博客积分: 2951
  • 博客等级: 少校
  • 技术积分: 1875
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 18:32
文章分类

全部博文(130)

文章存档

2013年(1)

2012年(129)

分类: Java

2012-02-27 11:52:35

public interface Map

将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

此接口取代 Dictionary 类,后者完全是一个抽象类,而不是一个接口。

Map 接口提供三种collection 视图,允许以键集、值集或键-值映射关系集的形式查看某个映射的内容。映射顺序 定义为迭代器在映射的 collection 视图上返回其元素的顺序。某些映射实现可明确保证其顺序,如 TreeMap 类;另一些映射实现则不保证顺序,如 HashMap 类。

Map

保存键值对成员,基于键找值操作,使用compareTocompare方法对键进行排序

HashMap

能满足用户对Map的通用需求

键成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

TreeMap

支持对键有序地遍历,使用时建议先用HashMap增加和删除成员,最后从HashMap生成TreeMap 附加实现了SortedMap接口,支持子Map等要求顺序的操作

键成员要求实现Comparable接口,或者使用Comparator构造TreeMap键成员一般为同一类型。

LinkedHashMap

保留键的插入顺序,用equals 方法检查键和值的相等性

成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。

 

  1. package intro.collections;

  2. import java.util.HashMap;
  3. import java.util.Iterator;
  4. import java.util.Map;
  5. import java.util.Set;

  6. public class MapTest {
  7.     public static void main(String[] args) {
  8.         Map map1 = new HashMap();
  9.         Map map2 = new HashMap();
  10.         map1.put("1","aaa1");
  11.         map1.put("2","bbb2");    
  12.         map2.put("10","aaaa10");
  13.         map2.put("11","bbbb11");
  14.         //根据键 "1" 取得值:"aaa1"    
  15.         System.out.println("map1.get(\"1\")="+map1.get("1"));
  16.         // 根据键 "1" 移除键值对"1"-"aaa1"
  17.         System.out.println("map1.remove(\"1\")="+map1.remove("1"));    
  18.         System.out.println("map1.get(\"1\")="+map1.get("1"));
  19.         map1.putAll(map2);//将map2全部元素放入map1中
  20.         map2.clear();//清空map2
  21.         System.out.println("map1 IsEmpty?="+map1.isEmpty());
  22.         System.out.println("map2 IsEmpty?="+map2.isEmpty());
  23.         System.out.println("map1 中的键值对的个数size = "+map1.size());
  24.         System.out.println("KeySet="+map1.keySet());//set
  25.         System.out.println("values="+map1.values());//Collection
  26.         System.out.println("entrySet="+map1.entrySet());        
  27.         System.out.println("map1 是否包含键:11 = "+map1.containsKey("11"));    
  28.         System.out.println("map1 是否包含值:aaa1 = "+map1.containsValue("aaa1"));
  29.         
  30.         Set<Map.Entry<String, String>> set = map1.entrySet();
  31.         Iterator<Map.Entry<String, String>> iter = set.iterator();
  32.         while(iter.hasNext()){
  33.             Map.Entry<String, String> entry = iter.next();
  34.             System.out.println(entry.getKey());
  35.             System.out.println(entry.getValue());            
  36.         }
  37.     }

  38. }

再看看排序的Map是如何使用

  1. package intro.collections;

  2. import java.util.HashMap;
  3. import java.util.LinkedHashMap;
  4. import java.util.Map;
  5. import java.util.TreeMap;

  6. public class SortedMapTest {
  7.     public static void main(String args[]) {
  8.         Map map1 = new HashMap();
  9.         Map map2 = new LinkedHashMap();
  10.         for (int i = 0; i < 10; i++) {
  11.             double s = Math.random() * 100;// 产生一个随机数,并将其放入Map中
  12.             map1.put(new Integer((int) s), "第 " + i + " 个放入的元素:" + s + "\n");
  13.             map2.put(new Integer((int) s), "第 " + i + " 个放入的元素:" + s + "\n");
  14.         }

  15.         System.out.println("未排序前HashMap:" + map1);
  16.         System.out.println("未排序前LinkedHashMap:" + map2);
  17.         // 使用TreeMap来对另外的Map进行重构和排序
  18.         Map sortedMap = new TreeMap(map1);
  19.         System.out.println("排序后:" + sortedMap);
  20.         System.out.println("排序后:" + new TreeMap(map2));
  21.     }
  22. }

未排序前HashMap:{0=第 3 个放入的元素:0.46674461834753656

, 34=第 2 个放入的元素:34.54670083072801

, 50=第 9 个放入的元素:50.82172311275165

, 80=第 7 个放入的元素:80.08590191596085

, 37=第 6 个放入的元素:37.810256398638984

, 22=第 5 个放入的元素:22.805908526261852

, 97=第 1 个放入的元素:97.2777359407105

, 92=第 8 个放入的元素:92.23124191087155

, 10=第 0 个放入的元素:10.331082717129602

}

未排序前LinkedHashMap:{10=第 0 个放入的元素:10.331082717129602

, 97=第 1 个放入的元素:97.2777359407105

, 34=第 2 个放入的元素:34.54670083072801

, 0=第 3 个放入的元素:0.46674461834753656

, 22=第 5 个放入的元素:22.805908526261852

, 37=第 6 个放入的元素:37.810256398638984

, 80=第 7 个放入的元素:80.08590191596085

, 92=第 8 个放入的元素:92.23124191087155

, 50=第 9 个放入的元素:50.82172311275165

}

排序后:{0=第 3 个放入的元素:0.46674461834753656

, 10=第 0 个放入的元素:10.331082717129602

, 22=第 5 个放入的元素:22.805908526261852

, 34=第 2 个放入的元素:34.54670083072801

, 37=第 6 个放入的元素:37.810256398638984

, 50=第 9 个放入的元素:50.82172311275165

, 80=第 7 个放入的元素:80.08590191596085

, 92=第 8 个放入的元素:92.23124191087155

, 97=第 1 个放入的元素:97.2777359407105

}

排序后:{0=第 3 个放入的元素:0.46674461834753656

, 10=第 0 个放入的元素:10.331082717129602

, 22=第 5 个放入的元素:22.805908526261852

, 34=第 2 个放入的元素:34.54670083072801

, 37=第 6 个放入的元素:37.810256398638984

, 50=第 9 个放入的元素:50.82172311275165

, 80=第 7 个放入的元素:80.08590191596085

, 92=第 8 个放入的元素:92.23124191087155

, 97=第 1 个放入的元素:97.2777359407105

}


    从运行结果,我们可以看出,HashMap的存入顺序和输出顺序无关。而LinkedHashMap 则保留了键值对的存入顺序。TreeMap则是对Map中的元素进行排序。在实际的使用中我们也经常这样做:使用HashMap或者LinkedHashMap 来存放元素,当所有的元素都存放完成后,如果使用则是需要一个经过排序的Map的话,我们再使用TreeMap来重构原来的Map对象。这样做的好处是:因为HashMap和LinkedHashMap 存储数据的速度比直接使用TreeMap 要快,存取效率要高。当完成了所有的元素的存放后,我们再对整个的Map中的元素进行排序。这样可以提高整个程序的运行的效率,缩短执行时间。
    这里需要注意的是,TreeMap中是根据键(Key)进行排序的。而如果我们要使用TreeMap来进行正常的排序的话,Key 中存放的对象必须实现Comparable 接口。

public class HashMapextends implements , ,

基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能。迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例。所以,如果迭代性能很重要,则不要将初始容量设置得太高(或将加载因子设置得太低)。

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

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

如果很多映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。

public class LinkedHashMapextends implements

Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。注意,如果在映射中重新插入 键,则插入顺序不受影响。(如果在调用 m.put(k, v) 前 m.containsKey(k) 返回了 true,则调用时会将键 k 重新插入到映射 m 中。)

此实现可以让客户避免未指定的、由 (及 )所提供的通常为杂乱无章的排序工作,同时无需增加与 相关的成本。使用它可以生成一个与原来顺序相同的映射副本,而与原映射的实现无关:

void foo(Map m) { Map copy = new LinkedHashMap(m); ... } 如果模块通过输入得到一个映射,复制这个映射,然后返回由此副本确定其顺序的结果,这种情况下这项技术特别有用。(客户通常期望返回的内容与其出现的顺序相同。)

提供特殊的来创建链接哈希映射,该哈希映射的迭代顺序就是最后访问其条目的顺序,从近期访问最少到近期访问最多的顺序(访问顺序)。这种映射很适合构建 LRU 缓存。调用 put 或 get 方法将会访问相应的条目(假定调用完成后它还存在)。putAll 方法以指定映射的条目集迭代器提供的键-值映射关系的顺序,为指定映射的每个映射关系生成一个条目访问。任何其他方法均不生成条目访问。特别是,collection 视图上的操作 影响底层映射的迭代顺序。

可以重写 方法来实施策略,以便在将新映射关系添加到映射时自动移除旧的映射关系。

此类提供所有可选的 Map 操作,并且允许 null 元素。与 HashMap 一样,它可以为基本操作(add、contains 和 remove)提供稳定的性能,假定哈希函数将元素正确分布到桶中。由于增加了维护链接列表的开支,其性能很可能比 HashMap 稍逊一筹,不过这一点例外:LinkedHashMap 的 collection 视图迭代所需时间与映射的大小 成比例。HashMap 迭代时间很可能开支较大,因为它所需要的时间与其容量 成比例。

链接的哈希映射具有两个影响其性能的参数:初始容量加载因子。它们的定义与 HashMap 极其相似。要注意,为初始容量选择非常高的值对此类的影响比对 HashMap 要小,因为此类的迭代时间不受容量的影响。

public class TreeMapextends implements , ,

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


阅读(2281) | 评论(0) | 转发(0) |
0

上一篇:tbd

下一篇:JAVA 集合框架 - hashCode

给主人留下些什么吧!~~