Java:浅谈 Map

33 篇文章 1 订阅

Map 翻译成中文是 映射。

映射的数学解释:

  设 A,B 是两个非空集合,如果存在一个法则 f,使得对 A 中的每个元素 a,按法则 f,在 B 中有唯一确定的元素 b 与之对应,则称 f 为从 A 到 B 的映射,记作 f:A ——> B。

映射关系(两个集合):A 集合和 B 集合

A 集合中的每一个元素都可以在 B 集合中找到唯一的一个值与之对应。

  严格说,Map 并不是集合,而是两个集合之间的映射关系(Map 接口并没有继承于 Collection 接口)然而因为 Map 可以存储数据(每次存储都应该存储 A 集合中以一个元素(key),B 集合中一元素(value)),我们还是习惯把 Map 也称为集合。

因为 Map 接口并没有继承于 Collection 接口也没有集成 Iterable 接口,所以不能直接对 Map 使用 for-each 操作。

Map 由多个 Entry 组成,把多个 Entry 看成一个集合,即:

Set<Entry> –> Map

Entry:key——value(键值对)
Map就是多个键值对的集合

在 Map 和 Set 中有很多相似的实现类名:

SetMap算法
HashSetHashMap哈希表
TreeSetTreeMap红黑树
LinkedHashSetLinkedHashMap哈希表/链表

  如果集合前缀相同,说明底层算法是一样的,现在单独使用 HashSet 和 HashMap 来研究,通过阅读源代码,发现,相同算法的 Set 底层用的是相同算法的 Map,把 Set 的集合对象作为 Map 的 key,再使用一个 Object 常量作为 value。
因此:在 Map 中,所有的 key 就是一个 Set 集合。

HashSet 源代码算法:
public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}

Map 的常用实现类:

HashMap:

采用哈希表算法,此时 Map 中的 key 不会保证添加的先后顺序,key 也不允许重复,key 判断重复的标准是 key1 和 key2 是否 equals 为 true,并且 hashCode 相等。

HashMap 判断 key 重复算法:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}   
TreeMap:

常用红黑树算法,此时 Map 中的 key 会按照自然顺序或定制排序进行排序,key 也不允许重复,key 判断重复的标准是:compareTo/compare 的返回值是否为 0。

TreeMap 判断 key 重复算法:
public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        compare(key, key); // type (and possibly null) check

        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry<K,V> parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    Entry<K,V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}
LinkedHashMap:

采用链表和哈希表算法,此时 Map 中的 key 类保证先后添加顺序,key 不允许重复,key 判断重复的标准和 HashMap 中的 key 的标准相同。

Hashtable:

采用哈希表算法,是 HashMap 的前身(类似于 Vector 是 ArrayList 的前身):在 Java 的集合框架之前,表示映射关系就使用 Hashtable。所有的方法都使用 synchronized 修饰符,线程安全的,但是性能相对 HashMap 较低。
PS:Hashtable 在 JDK1.0 就出来了,而 Map 类在 JDK1.2 才出来。

Properties:

Hashtable 的子类,此时要求 key 和 value 都是 String 类型,用来加载资源文件(properties 文件(IO))

Properties 源代码:
public synchronized Object setProperty(String key, String value) {
    return put(key, value);
}

注:一般的,定义 Map 的 key 都使用不可变的类(String),把 key 作为 value 的唯一名称。

HashMap 和 TreeMap 以及 LinkedHashMap 都是线程不安全的,但是性能较高。
解决方案:Map m = Collection.synchronizedMap(Map 对象)
Hashtable 类实现类线程安全的,但是性能较低。

附:

哈希表算法:做等值查询最快。
树结构算法:做范围查询最快———>应用到数据库索引上。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值