博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java之Set集合的"怪"
阅读量:6249 次
发布时间:2019-06-22

本文共 1874 字,大约阅读时间需要 6 分钟。

工作中可能用Set比较少,但是如果用的时候,出的一些问题很让人摸不着头脑,然后我就看了一下Set的底层实现,大吃一惊。 ###看一个问题

Map map = new HashMap();        map.put(1,"a");        map.put(12,"ab");        map.put(123,"abc");        Set set1 = map.keySet();        Set set2 = map.keySet();        Set set3 = map.keySet();        set1.remove(1);        set1.forEach(p-> System.out.println(p.toString()));        set2.forEach(p-> System.out.println(p.toString()));        set3.forEach(p-> System.out.println(p.toString()));复制代码

然后我的运行结果是

12312----------------12312----------------12312复制代码

为什么我在set1里面执行remove(1);其它的两个set对象为什么也删掉了第一个元素呢? 为什么会受到我前面操作的影响呢。 ###分析底层实现

1.最简单的实践

我们大概能猜出问题的所在,就是set1其实调用的还是map对象。那怎样才具有说服力呢。 学过反射的应该都清楚,我们可以看下set1它到底是什么类型的对象。

Class classes = set1.getClass();        System.out.println(classes.getTypeName());复制代码

控制台打印:

java.util.HashMap$KeySet复制代码

是不是眼前一亮,wtf竟然是个Map类型。我不是明明给它实例化了个Set对象吗。好了,这个现象成功吸引了我的兴趣。于是

找底层实现

我们找到这个KeySet方法

public Set
keySet() { Set
ks = keySet; if (ks == null) { ks = new AbstractSet
() { public Iterator
iterator() { return new Iterator
() { private Iterator
> 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; }复制代码

我们可以看到,有一个成员内部类AbstractSet(),里面有两部分,一部分是new 一个迭代器(内部类),一部分是调用AbstractMap对象(外部类)。外部类对象调用的内部类的构造函数,反编译的话,会看出传入了外部类对象的引用进去。所以它最终的类型应该是AbstractMap,(Map的派生类)。

所以,眼看是实例化了一个Set对象,其实底层还是调用的map对象。

转载地址:http://yywsa.baihongyu.com/

你可能感兴趣的文章
xming + putty 搭建远程图形化ssh访问ubuntu 14.04
查看>>
php 自带过滤和转义函数
查看>>
javascript一些小技巧
查看>>
android 使用HttpURLConnection方式提交get/post请求
查看>>
CTR预估中GBDT与LR融合方案
查看>>
I00024 出钱买羽
查看>>
原生js实现点击下载图片
查看>>
WinCE winform 开发注意事项
查看>>
linux下文件的一些文件颜色的含义
查看>>
OLTP系统的Oracle RAC性能调优,索引分区极大提升提交性能
查看>>
Leetcode | Binary Tree Zigzag Level Order Traversal
查看>>
websotrm注册码
查看>>
迭代器(Iterable)和for..in..的三种协议
查看>>
Gephi可视化(一)——使用Gephi Toolkit创建Gephi应用
查看>>
判断浏览器是否为顶层窗口
查看>>
数据结构化与保存
查看>>
跨域iframe高度自适应(兼容IE/FF/OP/Chrome)
查看>>
没有发布过产品的程序员不知道什么是真正的软件
查看>>
图论 - Travel
查看>>
服务器设计笔记(3)-----消息队列
查看>>