Java中Map接口及实现

来源:互联网 发布:淘宝时光机 编辑:程序博客网 时间:2024/04/29 10:07
  1. Map接口
   Map是从键到值的映射,键不允许重复,每个键最多能映射一个值.
public interface Map<K,V> {
    // Query Operations

    int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    V get(Object key);

    // Modification Operations
    V put(K key, V value);
    V remove(Object key);

    // Bulk Operations

    void putAll(Map<? extends K, ? extends V> t);
    void clear();

    // Views
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();

    interface Entry<K,V> {
 
 K getKey();
 V getValue();
 V setValue(V value);
 boolean equals(Object o);
 int hashCode();
    }

    // Comparison and hashing
    boolean equals(Object o);
    int hashCode();
}

  Entry接口及实现
    Map是键到值的映射,Java集合框架在实现上采用一个个Map.Entry来封装每一个键值对,这样,Map中的元素就变成了Map.Entry的集了,这似乎预示着Map和Set有某种相通性.实际上,在HashSet实现中,HashSet的实现中,HashSet的元素存储在底层就是借助于HashMap来进行的(在部分情况下使用了LinkedHashMap).
  //AbstractMap中的SimpleEntry类
  static class SimpleEntry<K,V> implements Entry<K,V> {
 K key;
 V value;

 public SimpleEntry(K key, V value) {
     this.key   = key;
            this.value = value;
 }

 public SimpleEntry(Entry<K,V> e) {
     this.key   = e.getKey();
            this.value = e.getValue();
 }

 public K getKey() {
     return key;
 }

 public V getValue() {
     return value;
 }

 public V setValue(V value) {
     V oldValue = this.value;
     this.value = value;
     return oldValue;
 }

 public boolean equals(Object o) {
     if (!(o instanceof Map.Entry))
  return false;
     Map.Entry e = (Map.Entry)o;
     return eq(key, e.getKey()) && eq(value, e.getValue());
 }

 public int hashCode() {
     return ((key   == null)   ? 0 :   key.hashCode()) ^
     ((value == null)   ? 0 : value.hashCode());
 }

 public String toString() {
     return key + "=" + value;
 }

        private static boolean eq(Object o1, Object o2) {
            return (o1 == null ? o2 == null : o1.equals(o2));
        }
    }
  2.Map的实现
    在java 2集合框架中的Map接口有两个通用实现:HashMap和TreeMap. HashMap是采用哈希表实现,是Map接口的最好的全面实现.TreeMap实现了Map的子接口SortedMap,采用红黑树作为底层存储结构,提供了按照键排序的Map存储.
    2.1HashMap和Hashtable的对比:
                          HashMap               Hashtable
键和值是否允许空    允许   不允许
是否多线程同步     否   是

   但是HashMap可以通过如下方式方便地得到HashMap的一个同步视图:
     Map synMap = Collections.synchronizedMap (new HashMap(...));
  Hashtable已经经过再造,这是为了保持向后的兼容,保证老版本的程序能够继续正常允许;同时也方便Hashtable和新集合框架进行互操作(新的Hashtable实现了Map接口).正是因为Hashtable经过这些修改,反而使得它混合了新旧的很多特性,过于复杂,臃肿.
   新的Map接口采用了比原来Hashtable采用的Enumeration功能更加强大的Iterator遍历工具.
Enumeration现在也不推荐使用, 不仅是因为Enumeration没有提供遍历键或值时安全删除Hashtable中的元素的途径;并且Enumeration的名称也不符合Sun的Java命名规范(采用Enumeration更加合适).而Hashtable为了兼容两者,在实现时,不得不提供同时实现了Enumeration和Iterator接口的Enumeration内部类.所以推荐大家用HashMap.
   2.2 TreeMap
   TreeMap中的Tree是一颗平衡二叉树,即每个内部节点都有一个前导节点或者说或者说父节点和两个子节点.存储后继节点的那个成员被命名为left和right. 二叉树在平衡时或者叶子节点到根结点的高度在一定的范围内时工作起来是最有效的.平衡一个二叉树的原因是为了缩短从根结点(这是在 TreeMap类中惟一能够被直接引用的结点)至每个叶子节点的距离.距离越短,访问那个节点所需时间就会越少.平衡树的定义因实现而异.java2 集合框架中的树采用红黑树.红黑树是一种平衡树,这个平衡树的定义是没有一个叶子节点跟其他叶子节点的深度差超过两步.这个名字就是由于树的每个节点都被着上红色和黑色,节点所着的颜色被用来检测树的平衡性.在对节点插入和删除的操作中,可能会被旋转来保持树的平衡性.一般和最坏情况插入,删除,查找时间都是O(lgn).
  TreeMap的put方法:
   public V put(K key, V value) {
        Entry<K,V> t = root;

        if (t == null) {
            incrementSize();
            root = new Entry<K,V>(key, value, null);
            return null;
       }

        while (true) {
            int cmp = compare(key, t.key);
            if (cmp == 0) {
                return t.setValue(value);
            } else if (cmp < 0) {
                if (t.left != null) {
                    t = t.left;
                } else {
                    incrementSize();
                    t.left = new Entry<K,V>(key, value, t);
                    fixAfterInsertion(t.left);
                    return null;
                }
            } else { // cmp > 0
                if (t.right != null) {
                    t = t.right;
                } else {
                    incrementSize();
                    t.right = new Entry<K,V>(key, value, t);
                    fixAfterInsertion(t.right);
                    return null;
                }
            }
        }
    }
  2.3 Map实现的选用
   在不需要有序存储时,可以采用高效的HashMap;如果需要有序存储,可以采用TreeMap,但是由于TreeMap是以红黑树进行存储的,需要比HashMap更多的空间和时间的开销.

原创粉丝点击