开发者社区> 微笑着生活> 正文

Java之Set集合的"怪"

简介: 工作中可能用Set比较少,但是如果用的时候,出的一些问题很让人摸不着头脑,然后我就看了一下Set的底层实现,大吃一惊。 看一个问题 Map map = new HashMap(); map.
+关注继续查看

工作中可能用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()));

然后我的运行结果是

123
12
----------------
123
12
----------------
123
12

为什么我在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<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;
    }

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

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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Java集合学习3:Set集合-TreeSet
基于hashcode计算元素存放位置。 当存入元素的哈希码相同时,会调用equals进行确认,如果为true,则拒绝后者存入。
23 0
Java集合学习3:Set集合-HashSet
无序、无下标、不可以重复元素 方法:全部继承Collection的方法
9 0
Java集合中List,Set以及Map(三者的区别,什么时候用Set,Connection接口)
Java集合中List,Set以及Map(三者的区别,什么时候用Set,Connection接口)
27 0
Java基础:浅析List、Set、Map的特点和区别(整合版)(下)
Java基础:浅析List、Set、Map的特点和区别(整合版)(下)
29 0
Java基础:浅析List、Set、Map的特点和区别(整合版)(上)
Java基础:浅析List、Set、Map的特点和区别(整合版)
32 0
《我要进大厂》- Java集合夺命连环14问,你能坚持到第几问?(集合概述 | List | Set | Queue)
《我要进大厂》- Java集合夺命连环14问,你能坚持到第几问?(集合概述 | List | Set | Queue)
33 0
Java集合(5)--Set接口及其实现类HashSet、LinkedHashSet和TreeSet
Java集合(5)--Set接口及其实现类HashSet、LinkedHashSet和TreeSet
24 0
Java集合-Set
Java集合-Set
28 0
Java中利用Set判断List集合中是否有重复元素
在开发工作中,我们有时需要去判断List集合中是否含有重复的元素
456 0
Map与Set高频面试算法题(只出现一次的数字,复制带随机指针的链表,宝石与石头,旧键盘,前k个高频单词)(Java实现)
给一个非空整数数组,只有一个元素出现了一次,剩余的元素都出现了两次,,请找出那个只出现一次的数字
53 0
+关注
微笑着生活
快乐开发
文章
问答
文章排行榜
最热
最新
相关电子书
更多
Java工程师必读手册
立即下载
Java应用提速(速度与激情)
立即下载
Java单元测试实战
立即下载