EnumMap 源码分析
EnumMap
EnumMap 能解决什么问题?什么时候使用 EnumMap?
1)EnumMap【枚举映射】中的键值必须来自单个枚举。
2)EnumMap 根据枚举键的自然顺序来维护,迭代遍历是有序的。
3)不允许使用 null 键,允许使用 null 值,内部会进行 mask 处理。
4)EnumMap 的键和值都通过对象数组来存储,读写性能高。
如何使用 EnumMap?
1)对象间映射关系的键来自单个枚举时,可以使用 EnumMap。
使用 EnumMap 有什么风险?
1)键和值的长度是根据枚举类型的元素个数确定的,可能存在一定的内存浪费。
EnumMap 核心操作的实现原理?
- 创建实例
/**
* 枚举键的 Class 类型
*/
private final Class<K> keyType;
/**
* 枚举键的所有有效枚举值组成的数组
*/
private transient K[] keyUniverse;
/**
* 底层存储值的对象数组
*/
private transient Object[] vals;
/**
* 映射总数
*/
private transient int size = 0;
/**
* 通过指定的键枚举类型创建空的枚举映射
*/
public EnumMap(Class<K> keyType) {
this.keyType = keyType;
// 缓存所有的枚举值数组
keyUniverse = EnumMap.getKeyUniverse(keyType);
// 创建存储值的对象数组
vals = new Object[keyUniverse.length];
}
- 添加元素
private static final Object NULL = new Object() {
@Override
public int hashCode() {
return 0;
}
@Override
public String toString() {
return "java.util.EnumMap.NULL";
}
};
private Object maskNull(Object value) {
return value == null ? NULL : value;
}
@SuppressWarnings("unchecked")
private V unmaskNull(Object value) {
return (V)(value == NULL ? null : value);
}
/**
* 往枚举映射中添加元素
*/
@Override
public V put(K key, V value) {
typeCheck(key);
// 获取键的自然顺序
final int index = key.ordinal();
// 读取旧值
final Object oldValue = vals[index];
// 写入新值
vals[index] = maskNull(value);
// 如果之前为该 slot 为空
if (oldValue == null) {
// 则增加计数值
size++;
}
// 返回 旧值
return unmaskNull(oldValue);
}
- 读取元素
/**
* 根据目标键读取值
*/
@Override
public V get(Object key) {
/**
* 1)键合法则读取指定索引处的值,并 mask 后返回
* 2)键非法则返回 null
*/
return isValidKey(key) ?
unmaskNull(vals[((Enum<?>)key).ordinal()]) : null;
}
/**
* 校验键是否合法
*/
private boolean isValidKey(Object key) {
// 枚举映射的键不能为 null
if (key == null) {
return false;
}
// Cheaper than instanceof Enum followed by getDeclaringClass
// 校验键的类型是否合法
final Class<?> keyClass = key.getClass();
return keyClass == keyType || keyClass.getSuperclass() == keyType;
}
- 移除元素
/**
* 1)如果指定的枚举键存在,则移除并返回旧值
* 2)否则返回 null
*/
@Override
public V remove(Object key) {
// 1)键非法则返回 null
if (!isValidKey(key)) {
return null;
}
// 读取枚举键的自然顺序
final int index = ((Enum<?>)key).ordinal();
// 读取旧值
final Object oldValue = vals[index];
// 置空
vals[index] = null;
if (oldValue != null) {
// 如果存在旧值,则递减元素总个数
size--;
}
return unmaskNull(oldValue);
}
- 是否包含指定键
/**
* 枚举映射包含指定的键
*/
@Override
public boolean containsKey(Object key) {
// 键合法并且以目标键的自然顺序为索引,读取 vals 中的值不为 null
return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
}
- 是否包含指定值
/**
* 值数组中是否包含指定的值
*/
@Override
public boolean containsValue(Object value) {
value = maskNull(value);
for (final Object val : vals) {
if (value.equals(val)) {
return true;
}
}
return false;
}
EnumMap 源码分析的更多相关文章
- Openrasp源码分析
Openrasp是百度关于rasp技术的开源项目,由于工作需要,之前对rasp的源码进行了简单的分析.文章是之前就写好的,现在放出了,希望对大家有写帮助. OpenRASP中java引擎的源码分析 安 ...
- Springboot学习04-默认错误页面加载机制源码分析
Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ...
- JDK集合框架源码分析 - 简单概要
1.类继承体系 在集合框架的类继承体系中,最顶层有两个接口Collection.Map: Collection 表示一组纯数据 Map 表示一组key-value对 Collection的类继承体系: ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- zookeeper源码分析之三客户端发送请求流程
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
随机推荐
- Python 入门之 Python三大器 之 生成器
Python 入门之 Python三大器 之 生成器 1.生成器 (1)什么是生成器? 核心:生成器的本质就是一个迭代器 迭代器是Python自带的 生成器程序员自己写的一种迭代器 def func( ...
- Android remote gdb
On Android phone adb push ~/utils/android-ndk-r12b/prebuilt/android-arm64/gdbserver/gdbserver /data/ ...
- 02.AutoMapper 之扁平化(Flattening)
https://www.jianshu.com/p/65099590c930 扁平化(Flattening) 对象映射器的常见用法是将一个复杂对象模型扁平化为一个简单模型.例如您有一个以下复杂模型 ...
- ambari 2.5.0源码编译安装
参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-bigdata-ambari/index.html Ambari 是什么 Ambar ...
- 【学习总结】快速上手Linux玩转典型应用-第5章-远程连接SSH专题
课程目录链接 快速上手Linux玩转典型应用-目录 目录 1. 认识SSH 2. 服务器安装SSH服务 3. 客户端安装SSH工具 4. 客户端链接SSH服务 5. SSH config 6. SSH ...
- react找到对象数组中指定的值
找到对象数组中指定的值var array = [ { label: "Custom", value: "0" }, ...
- HTML-美化
1.美化文本 1.1第一部分 font-size:字体大小,常用em.px.%.rem作单位,预设值small.large.medium,可继承, font-weight:加粗字体,属性为bold,加 ...
- jQuery进阶第四天(2019 10.13)
1 初识面向对象(面向对象是一种思维方式) 以前写的代码 var name = '莉莉'; var sex = '女'; var age = 18; var name1 = '小明'; var sex ...
- make_smbcodepage - 为Samba创建代码页文件
总览 make_smbcodepage c|d 代码页 输入文件 输出文件 描述 这个工具是是Samba组件的一部分. 针对Samba 2.2的国际化功能,使用make_smbcodepage可以编译 ...
- ubuntu下安装3.6.5
1.下载python3.6.5安装包 地址:https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz 解压:tar -xvzf Python-3 ...