Java集合框架概述(四)——Map体系集合与底层实现原理

一、Map父接口

1.概要

方法 描述
public interface Map<K,V> 将键映射到值的对象。 一个映射不能包含重复的键; 每个键可以映射到最多一个值。

 将键映射到值的对象。 Map不能包含重复的键; 每个键可以映射到最多一个值。
Map界面提供了三个collection视图 ,允许将映射内容视为键键、值集或键-值映射关系集。 映射的顺序定义在迭代器在映射的collection示图上返回其元素的顺序。某些映射实现可明确保证其顺序,如TreeMap类,另一些映射实现则不保证顺序,如HashMap

在这里插入图片描述

Map接口的继承关系

2.Map接口的特点:

  • 用于存储任意键值对(Key-Value)
  • 键:无序、无下标、不允许重复(唯一)
  • 值:无序、无下标、允许重复
    在这里插入图片描述

3.Map常见方法

方法 描述
V put(K key, V value) 将对象存入集合中,关联键值。key重复则覆盖原值
V get(Object key) 如果此映射包含该键的映射,返回到指定键所映射的值,或 null。
Set keySet() 返回此Map中所有的Key
Collection values() 返回包含所有值的Collection集合
Set<Map.Entry<K,V>> entrySet() 键值匹配的Set集合

4.应用场景

 在进行字典查询时,通过List接口的下标查询已经不能满足要求,因为用户不能根据元素下标轻松查询到对应位置的值,两者在直观性并不强。

public class CountryMap {

    public static void main(String[] args){
        System.out.println("请输入国家的缩写:");
        Scanner scanner = new Scanner(System.in);

        String s = Country.countries.get(scanner.nextLine());
        System.out.println("查询结果为:"+s);
    }
}
class Country{
    public static final Map<String,String> countries = new HashMap<>();
    static {
        countries.put("CN","中华人民共和国");
        countries.put("US","美利坚合众国");
        countries.put("KR","韩国");
        countries.put("JP","日本");
    }
}

打印结果:
在这里插入图片描述

5.keySet()方法和Values()方法

 在要点3中罗列出了keySet()方法和Values()方法,两者分别表示返回所有键、返回所有值,但是前者接收的方式是Set集合,后者则是Collection结合。原因在于:Key是唯一的,Value是不唯一且无序的

public class CountryMap {

    public static void main(String[] args){
        //所有键(Key是唯一的,因此时Set接收)
        Set<String> keys = Country.countries.keySet();
        System.out.println(keys);
        //所有值(值是无序的,且是不唯一的)
        Collection<String> values = Country.countries.values();
        System.out.println(values);
    }
}
class Country{
    public static final Map<String,String> countries = new HashMap<>();
    static {
        countries.put("CN","中华人民共和国");
        countries.put("US","美利坚合众国");
        countries.put("KR","韩国");
        countries.put("JP","日本");
    }
}

打印结果:
在这里插入图片描述

二、Map的实现类

1.HashMap

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

  • JDK1.2版本,线程不安全,运行效率快;允许使用null作为Key或者是value

 HashSet是对HashMap的实现:
 用户所有存进HashSet中的值,HashSet会原封不动的提交给HashMap的Key,进而根据Key来进行排序

public class HashSet<E> extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    private transient HashMap<E,Object> map;
}

public boolean add(E e) {
	return map.put(e, PRESENT)==null;
}

2.Hashtable

 该类实现了一个哈希表,它将键映射到值。 任何非null对象都可以用作键值或值。
为了从散列表成功存储和检索对象,用作键的对象必须实现hashCode方法和equals方法。

  • JDK1.0版本,线程安全,运行效率慢;不允许使用null作为Key或者是value

3.TreeMap

 该方法可以讲Map中的键值对按照键值的进行自然排序;同样的,根据HashMap和HashSet的关系,事实上TreeSet是基于TreeMap的实现,即用户所有存进TreeSet中的值,TreeSet会原封不动的提交给TreeMap的Key,进而根据Key来进行排序。

//伪代码
class TreeSet<E>{
	private TreeMap<E,?> map;
	public void add(E,e){
		map.put(e,null);
	}
}
calss TreeMap<K k ,V v>{
	public void put(K k, V v){
	}
}

三、Map的真面目——数组链表

 前面我们使用了keySet()方法和Values()方法来分别返回Map的所有键和所有值,那怎样但返回所有 键-值对呢?显然,会使用到Set<Map.Entry<K,V>> entrySet()方法。
 该方法的返回类型是Set,但是与Values()方法不同的是,Set的泛型一个Map.Entry<K,V>也是一个泛型,这里就涉及到了Map的底层实现原理了

 JDK1.8中,用户所有存入Map的键值都会存入Node<K,V>[]类型的table数组,而Node<K,V> 实现了Map.Entry<K,V>,实质上Map本身是一个数组。(JDK1.7中使用的不是Node<K,V>[]而是Entry<K,V>

 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

 默认的数组的长度为16,且每个元素都有对应的类型就是Entry<K,V>,当用户在new一份新的HashMap对象时,会把HashMap<K,V>对应的值传给Entry<K,V>

/**
	*该表在首次使用时初始化,并调整为
     *必填。分配后,长度始终是2的幂。
     *(我们在某些操作中也允许长度为零,以允许
     *当前不需要的引导机制。)
     */
    transient Node<K,V>[] table;

    /**
	 *保存缓存的entrySet()。请注意,使用AbstractMap字段
     *用于keySet()和values()
     */
    transient Set<Map.Entry<K,V>> entrySet;
//公开的静态内部类
static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }

 横向看Map数组状,存储了16个主要元素,接着每一个元素下有挂靠了以链表结构存储的其他元素。
在这里插入图片描述
现因个人能力有限,具体详细分析可参考博文:

Java中HashMap底层实现原理(JDK1.8)源码分析

  • 应用:
public class CountryMap {

    public static void main(String[] args){
        //所有键和值
        Set<Map.Entry<String,String>> entries = Country.countries.entrySet();
        for (Map.Entry<String,String> entry: entries){
            System.out.println(entry);
        }
    }
}
class Country{
    public static final Map<String,String> countries = new HashMap<>();
    static {
        countries.put("CN","中华人民共和国");
        countries.put("US","美利坚合众国");
        countries.put("KR","韩国");
        countries.put("JP","日本");
    }
}

打印结果:
在这里插入图片描述

发布了82 篇原创文章 · 获赞 124 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_44717317/article/details/104707031