您的位置:首页 > 编程语言 > Java开发

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

2020-03-17 18:39 489 查看

一、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","日本");
}
}

打印结果:

  • 点赞 1
  • 收藏
  • 分享
  • 文章举报
Lukey Alvin 发布了84 篇原创文章 · 获赞 139 · 访问量 13万+ 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: