我们通常说,keySet()返回所有的键,values()返回所有的值,其实是不太对的,因为无论是keySet()和values(),其实都没有实质的内容,且容我慢慢说来。

他们前者返回了一个Set,后者返回了一个Collection,但是Set和Collection都只是接口,既然是接口,那就大有文章可以做。很重要的一点就是,接口可以不是new someClass()的来的,也就是说,它可以不对应与一个类,而只提供一些方法。实际上,HashMap中所有的数据都是放在一个Node<E,V>[]的数组中的,而返回的Set接口也好,Collection也罢,都是直接针对这个Node<E,V>[]数组的,所以,当使用返回的Set接口或者Collection接口进行操作是,实际上操作的还是那个Node<E,V>[]数组。但是,返回的Collection只能做有限的操作,限定哪些呢?一句话总结就是:只能读,不能写,但能删能清。

不信?我们可以看源码。

首先来看values方法:

public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new Values();
values = vs;
}
return vs;
}

可以看到values其实是返回了一个Values类的,这是个内部类,就在它后面:

    final class Values extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<V> iterator() { return new ValueIterator(); }
public final boolean contains(Object o) { return containsValue(o); }
public final Spliterator<V> spliterator() {
return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super V> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}

看到没有,完全没有提供新数据,完全是操作那个table,或者调用hashMap自己的方法。我之前傻呵呵的找源码是怎么为values(HashMap除了有values这个方法,还有一个属性也叫values,坑爹不?)赋值的,现在才知道自己是这么傻,因为根本就没有复制嘛。

再来看keySet,也是一样的思路:

     public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new KeySet();
keySet = ks;
}
return ks;
} final class KeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<K> iterator() { return new KeyIterator(); }
public final boolean contains(Object o) { return containsKey(o); }
public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;
}
public final Spliterator<K> spliterator() {
return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super K> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e.key);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}

java中HashMap的keySet()和values()的更多相关文章

  1. Java中HashMap遍历的两种方式

    Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...

  2. 【转】 java中HashMap详解

    原文网址:http://blog.csdn.net/caihaijiang/article/details/6280251 java中HashMap详解 HashMap 和 HashSet 是 Jav ...

  3. java中HashMap详解(转)

    java中HashMap详解 博客分类: JavaSE Java算法JDK编程生活       HashMap 和 HashSet 是 Java Collection Framework 的两个重要成 ...

  4. java集合(2)- java中HashMap详解

    java中HashMap详解 基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 H ...

  5. Java中HashMap的实现原理

    最近面试中被问及Java中HashMap的原理,瞬间无言以对,因此痛定思痛觉得研究一番. 一.Java中的hashCode和equals 1.关于hashCode hashCode的存在主要是用于查找 ...

  6. JAVA中hashmap的分析

    从http://blog.csdn.net/luanlouis/article/details/41576373?utm_source=tuicool&utm_medium=referral学 ...

  7. JAVA中HashMap相关知识的总结(一)

    Java中HashMap在jdk1.7和jdk1.8中的区别点: 在jdk1.7中是用数组+链表形式存储,1.8采用数组+链表/红黑树形式 Jdk1.8中由链表转为红黑树是长度大于8,由红黑树转为链表 ...

  8. java中HashMap的设计精妙在哪?

    摘要:本文结合图解和问题,教你一次性搞定HashMap 本文分享自华为云社区<java中HashMap的设计精妙在哪?用图解和几个问题教你一次性搞定HashMap>,作者:breakDaw ...

  9. java 中 HashMap 遍历与删除

    HashMap的遍历 方法一.这是最常见的并且在大多数情况下也是最可取的遍历方式 /** * 在键值都需要时使用 */ Map<Integer, Integer> map = new Ha ...

随机推荐

  1. 关于对SwfUpload的改造

    Swfupload 在普通上传下,对于IE chrome firefox等有很好的兼容性. 但一旦与其他控件组合,很容易出现无法上传,帮顶事件丢失的情况. 例如Layer与Swfupload,上传一个 ...

  2. subset子集全排序问题

    思路一 可以用递推的思想,观察S=[], S =[1], S = [1, 2] 时解的变化. 可以发现S=[1, 2] 的解就是 把S = [1]的所有解末尾添上2,然后再并上S = [1]里面的原有 ...

  3. 如何调用写好的指定模块?——sys.path

    python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...

  4. Linux简单部署svn服务

    最近需要练习一下svn的命令行使用方法,以便编写自动化部署的脚本,但是不敢用正式的svn库进行练习,所以自己部署了一个svn服务,用来练习 1.安装svn server 我用的是ubuntu $apt ...

  5. 【bzoj4872】[Shoi2017]分手是祝愿 期望dp

    Description Zeit und Raum trennen dich und mich. 时空将你我分开.B 君在玩一个游戏,这个游戏由 n 个灯和 n 个开关组成,给定这 n 个灯的初始状态 ...

  6. python中文件路径的问题

    慎用中文路径!慎重中文路径!!慎用中文路径!!! good = np.loadtxt(u'D:/feiq/feiq/Recv Files/Recv Files/LOS 数据集/good_user2', ...

  7. 解决vs code中golang插件依赖安装失败问题

    解决vs code中golang插件依赖安装失败问题 Installing github.com/nsf/gocode SUCCEEDED Installing github.com/uudashr/ ...

  8. ubuntu 16.04 安装googlepinyin中文输入法

    安装谷歌拼音输入法 打开终端输入: apt-get install fcitx-googlepinyin 安装完成之后,进入系统设置 安装语言包 修改输入法系统 点击“System Setting”- ...

  9. 20165224 陆艺杰 Exp5 MSF基础应用

    用自己的话解释什么是exploit,payload,encode Exploit是攻击的行为 Payload是一段植入目标机的简短的带功能的恶意代码 Encode是编码,用于更改恶意代码,编码特征码检 ...

  10. ansible基本模块-server

    ansible   XXX   -m   service   -a  "name=XXX   state=started   enabled=yes"