Java源码记录 - AbstractMap
路径java.util.AbstractMap
()
构造方法
/**
* 唯一的构造器。(一般由子类隐式调用)
*/
protexted AbstractMap(){
}
size()
返回当前map的大小
public int size() {
return entrySet().size();
}
这里的
entrySet()
返回一个Set<Entry<K,V>>
对象。但是当前类AbstractMap
没有实现它。下同
isEmpty()
判断当前Map是否为空
public boolean isEmpty() {
return size() == 0;
}
containsKey(Object key)
是否包含指定key
public boolean containsKey(Object key) {
Iterator<Map.Entry<K,V>> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
return true;
}
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return true;
}
}
return false;
}
同样依靠
entrySet()
方法,使用迭代器检查每一个Entry
的Key值
当参数key为空时,有任何一个Entry的key值为空则返回true
当参数key不为空时,参数key的equals
方法与任何一个key返回true时本方法返回true
其他情况返回false
get(Object key)
获取指定val
public V get(Object key) {
Iterator<Entry<K,V>> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
return e.getValue();
}
} else {
while (i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
return e.getValue();
}
}
return null;
}
与
containsKey(Object key)
相同,返回值由bool变成了Entry
的getVale
的返回值
其他情况下,返回null
put(K key, V value)添加一个键值对
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
直接抛出异常UnsupportedOperationException
remove(Object key)
删除指定键值
public V remove(Object key) {
Iterator<Entry<K,V>> i = entrySet().iterator();
Entry<K,V> correctEntry = null;
if (key==null) {
while (correctEntry==null && i.hasNext()) {
Entry<K,V> e = i.next();
if (e.getKey()==null)
correctEntry = e;
}
} else {
while (correctEntry==null && i.hasNext()) {
Entry<K,V> e = i.next();
if (key.equals(e.getKey()))
correctEntry = e;
}
}
V oldValue = null;
if (correctEntry !=null) {
oldValue = correctEntry.getValue();
i.remove();
}
return oldValue;
}
基于
entrySet()
,获取到对应Entry
后,缓存其val,并在迭代器中删除找到的Entry
,然后返回val
putAll(Map<? extends K, ? extends V> m)
添加指定Map中的键值对到当前当前Map中
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
put(e.getKey(), e.getValue());
}
基于
entrySet()
,迭代调用put(K key, V value)
方法进行操作
本类中put(K key, V value)
的实现为直接抛出UnsupportedOperationException()
异常
clear() 清空Map
public void clear() {
entrySet().clear();
}
直接清空
entrySet()
所返回的Set
集合
视图keySet
与values
transient Set<K> keySet;
transient Collection<V> values;
这两个变量主要用于
keySet()
与values()
方法。
Set<K> keySet()
获取key
集合
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new AbstractSet<K>() {
public Iterator<K> iterator() {
return new Iterator<K>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public K next() {
return i.next().getKey();
}
public void remove() {
i.remove();
}
};
}
public int size() {
return AbstractMap.this.size();
}
public boolean isEmpty() {
return AbstractMap.this.isEmpty();
}
public void clear() {
AbstractMap.this.clear();
}
public boolean contains(Object k) {
return AbstractMap.this.containsKey(k);
}
};
keySet = ks;
}
return ks;
}
此方法会初始化成员变量
keySet
并保持它的单例(因为没有做同步处理,所以有可能在并发环境下返回不同的对象)。
此方法构造的Set
集合实际类型为AbstractSet
的匿名内部类,主要有如下实现
iterator()
方法的实现每次构造一个新的Iterator
对象,并在内部保存外部类的entrySet()
的iterator()
方法所返回的迭代器对象。作为委派目标i
- 新的Iterator对象的
hasNext()
,next()
,remove()
方法均委托到变量i
AbstractSet
其他的实现方法size()
,isEmpty()
,clear()
,contains(Object k)
全部委托到外部类AbstractMap
的同名方法这里发生了一次数据上的可能的分离,就是
iterator()
所返回对象内部对象i
来自entrySet().iterator()
,而此时其他的方法如size()
使用的实际方法为entrySet().size()
,有可能会发生数据不同步的情况
values() 获取值集合
public Collection<V> values() {
Collection<V> vals = values;
if (vals == null) {
vals = new AbstractCollection<V>() {
public Iterator<V> iterator() {
return new Iterator<V>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public V next() {
return i.next().getValue();
}
public void remove() {
i.remove();
}
};
}
public int size() {
return AbstractMap.this.size();
}
public boolean isEmpty() {
return AbstractMap.this.isEmpty();
}
public void clear() {
AbstractMap.this.clear();
}
public boolean contains(Object v) {
return AbstractMap.this.containsValue(v);
}
};
values = vals;
}
return vals;
}
与
keySet()
相同,只是返回类型换为允许重复元素的AbstractCollection
equals(Object o)
比较两个Map
是否相同
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Map))
return false;
Map<?,?> m = (Map<?,?>) o;
if (m.size() != size())
return false;
try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
比较流程如下
- 如果是同一个对象,则返回
true
- 如果入参不是
Map
的子类,直接返回false
- 如果两者的
size()
返回的数量不同,直接返回false
- 使用
entrySet().iterator()
获取当前对象的迭代器并进行迭代。进行如下操作- 迭代中。当val为空时,使用key向入参map进行值获取,结果值不为空或不包含这个key时,返回
false
- 迭代中。当val为不空时,使用key向入参map进行值获取,当使用
equals
比较两者不相同时,返回false
- 迭代中出现
ClassCastException
与NullPointerException
返回false
- 执行到结尾,返回
true
hashCode()
获取HashCode
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
迭代所有
Entry
,累加所有Entry
的HashCode
clone()
clone当前对象
protected Object clone() throws CloneNotSupportedException {
AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
result.keySet = null;
result.values = null;
return result;
}
注意,这里是浅拷贝,并对新对象的
keySet
与values
属性进行置空
由于当前抽象类的绝大多数实现是基于方法entrySet()
方法,所以这个方法需要由实现类进行关注。防止浅拷贝后,新对象指向老引用引发问题
Java源码记录 - AbstractMap的更多相关文章
- Java源码解读(一)——HashMap
HashMap作为常用的一种数据结构,阅读源码去了解其底层的实现是十分有必要的.在这里也分享自己阅读源码遇到的困难以及自己的思考. HashMap的源码介绍已经有许许多多的博客,这里只记录了一些我看源 ...
- 【java集合框架源码剖析系列】java源码剖析之java集合中的折半插入排序算法
注:关于排序算法,博主写过[数据结构排序算法系列]数据结构八大排序算法,基本上把所有的排序算法都详细的讲解过,而之所以单独将java集合中的排序算法拿出来讲解,是因为在阿里巴巴内推面试的时候面试官问过 ...
- JVM之---Java源码编译机制
Sun JDK中采用javac将Java源码编译为class文件,这个过程包含三个步骤: 1.分析和输入到符号表(Parse and Enter) Parse过程所做的工作有词法和语法分 ...
- 从Java源码到Java字节码
Java最主流的源码编译器,javac,基本上不对代码做优化,只会做少量由Java语言规范要求或推荐的优化:也不做任何混淆,包括名字混淆或控制流混淆这些都不做.这使得javac生成的代码能很好的维持与 ...
- 【JDK命令行 一】手动编译Java源码与执行字节码命令合集(含外部依赖引用)
写作目标 记录常见的使用javac手动编译Java源码和java手动执行字节码的命令,一方面用于应对 Maven 和 Gradle 暂时无法使用的情况,临时生成class文件(使用自己的jar包):另 ...
- 如何阅读Java源码 阅读java的真实体会
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比 ...
- Android反编译(一)之反编译JAVA源码
Android反编译(一) 之反编译JAVA源码 [目录] 1.工具 2.反编译步骤 3.实例 4.装X技巧 1.工具 1).dex反编译JAR工具 dex2jar http://code.go ...
- 如何阅读Java源码
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动.源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧, ...
- Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库
http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...
随机推荐
- Python正则表达式,看完这篇文章就够了...#华为云·寻找黑马程序员#【华为云技术分享】
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...
- luogu P2701 [USACO5.3]巨大的牛棚Big Barn |动态规划
题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N x N 的方格.输入数据中包括有树的 ...
- Word表格斜线怎么弄?这里有三种方法很实用
有些时候我们也会在Word文档中插入表格,因为这样可以准确的表达出文档中的内容.大家应该都知道Excel表格斜线怎么弄,那么Word表格斜线怎么弄吗?今天呢小编就帮大家总结了三种方法哦,有需要的小伙伴 ...
- BZOJ11208 宠物收养所
最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希 ...
- 洛谷 题解 P1025 【数的划分】
将n个小球放到k个盒子中的情况总数 = (a)至少有一个盒子只有一个小球的情况数 + (b)没有一个盒子只有一个小球的情况数 这样写出表达式: a.因为盒子不加区分,那么=情况数与"将n-1 ...
- vue实现双向绑定的基础方法
Vue2的组件props通信方式 在Vue2中组件的props的数据流动改为了只能单向流动,即只能由组件外(调用组件方)通过组件的DOM属性attribute传递props给组件内,组件内只能被动接收 ...
- 开局一张图,学一学项目管理神器Maven!
Maven强大的Java工程构建工具,做Java开发时少了跟Maven打交道,之前在知乎上看到有人提问:"学Java开发需不需要学习Maven?",个人认为是必需要学的,这和工欲善 ...
- ASP.NET Core开发者指南()
你可以在下面找到一张图,该图展示了你可以选取的路径及你想学习的库,从而成为一名 ASP.NET Core 开发者.“作为 ASP.NET Core 开发者,我接下来应该学习什么?”,我把这张图作为建议 ...
- 封装读取文件(node js)
我们都会简单的读取文件,今天我们就来讲一下用函数封装读取文件. 1.首先我们要先建好文件 2.我们在index.js里面写入代码: var http=require('http'); var fs=r ...
- hdu 1667 The Rotation Game ( IDA* )
题目大意: 给你一个“井”子状的board,对称的由24个方块组成,每个方块上有123三个数字中的一个.给你初始状态,共有八种变换方式,求字典序最小的最短的的变换路径使得,board中间的八个方块上数 ...