Java进阶(Set)——面试时Set常见问题解读 & 结合源码分析

前言

List、Set、HashMap作为Java中常用的集合,需要深入认识其原理和特性。

本篇博客介绍常见的关于Java中Set集合的面试问题,结合源码分析题目背后的知识点。

关于List的博客文章如下:

其他相关的Set的文章如下:

目录

  • 前言
  • 引出
  • [1. 描述一下HashSet的底层原理?](#1. 描述一下HashSet的底层原理?)
  • [2. map.put方法,静态常量PRESENT](#2. map.put方法,静态常量PRESENT)
  • [3. map.remove key方法,PRESENT进行比较](#3. map.remove key方法,PRESENT进行比较)
  • [4. HashSet的去重原理?](#4. HashSet的去重原理?)
  • [5. 如何选择HashSet 或 TreeSet?](#5. 如何选择HashSet 或 TreeSet?)
  • [6. 如何得到一个线程安全的Set集合?](#6. 如何得到一个线程安全的Set集合?)
  • 总结

引出


1.特点:无序,去重,非线程安全;

2.底层:HashMap的Key值实现的;

3.map.put方法,静态常量PRESENT,新值替换旧值;

4.map.remove key方法,如果KEY不存在时,则返回的是null,如果KEY存在时,返回的就是e.value,即PRESENT,返回true成功,返回false不成功;

5.去重原理:先判断hash值,再通过==或者equals判断,整体如果返回true,则为重复元素;

6.无序的则采用HashSet ,有序的则采用TreeSet;

7.线程安全的set:Collections.synchronizedSet(new HashSet<>());

1. 描述一下HashSet的底层原理?

  1. HashSet的特点:无序,去重,非线程安全
  2. HashSet 底层是用HashMap的Key值实现的,也有上面的3大特征;

构造方法

无参和代参构造方法都会初始化这个HashMap

无参的构造方法,调用了HashMap方法

有参的构造方法也是,调用了HashMap方法

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上

add方法

add方法中可以看出调用HashMap的put方法,key为放入元素,值为常量PRESENT

2. map.put方法,静态常量PRESENT

既然hashset基于hashmap实现,你说一下 hashset的add方法中,为什么要在map.put的val上放上一个Object类型的静态常量PRESENT?

HashSet底层调用了map的put方法,传入了存储的对象和PRESENT常量,那我们进入put方法继续查看

put方法内调用了putVal方法,PRESENT常量为形参value,继续进入查看

java 复制代码
	if (e != null) { // existing mapping for key
        //把旧数据存储到oldValue
        V oldValue = e.value;
        //如果说存储的位置上已经有元素了
        if (!onlyIfAbsent || oldValue == null)
            //新元素会替代旧元素   新KEY替代KEY
            e.value = value;
        afterNodeAccess(e);
        //返回旧元素数据
        return oldValue;
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    //如果说上面的if结构没有执行,那么就说明这个位置上没有元素,则新增成功,返回null
    return null;
java 复制代码
public boolean add(E e) {
        //上面的方法返回值决定了HashSet的add方法到底返回true还是false
        return map.put(e, PRESENT)==null;
    }
  1. 此方法内部明确箭头标处的原理,value就是PRESENT,如果进入这个if结构,则说明这个位置上已经存在该key,则会用value替换之前的旧值,然后返回旧值oldValue,否则会返回null;
  2. 至此,我们可以看出此方法的返回值是PRESENT或者是null,如果为PRESENT则说明KEY已存在,则add方法就会返回false(此处元素put还是成功的,只是新值替换旧值),返回null则add返回true,此KEY不存在,代表存储新的KEY-VALUE;

3. map.remove key方法,PRESENT进行比较

既然hashset基于hashmap实现,你说一下 hashset的remove方法中,为什么要在map.remove key 完了之后要和PRESENT进行一个等值比较呢?

  1. 从HashMap的remove方法中可以看出,方法返回的是e.value或者null,与add方法中的原理一起联想,则会明白,如果KEY不存在时,则返回的是null,如果KEY存在时,返回的就是e.value,即PRESENT
  2. 所以在HashSet在判断此返回值==PRESENT,如果相等则返回true,说明此KEY是存在的,删除成功返回true,如果返回值是null,那么null=PRESENT则返回的肯定是false,那么代表此KEY不存在,删除自然不成功,返回false;
java 复制代码
public V remove(Object key) {
        Node<K,V> e;
        //判断了一下,如果removeNode删除得到的是null,说明此KEY不存在,方法返回null
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            //否则返回e.value   就是 PRESENT
            null : e.value;
    }
java 复制代码
public boolean remove(Object o) {
        //因为HashMap删除成功返回的是PRESENT , ==PRESENT 则结果为true 代表删除成功
    //否则返回的是null , 返回false  删除失败
        return map.remove(o)==PRESENT;
    }

4. HashSet的去重原理?

  1. HashMap中putVal方法中有这么一段代码判断,去重原理在于hashcode的判断和equals方法的判断
  2. 先判断hash值,再通过==或者equals判断,整体如果返回true,则为重复元素

5. 如何选择HashSet 或 TreeSet?

无序的则采用HashSet ,有序的则采用TreeSet

6. 如何得到一个线程安全的Set集合?

Set datas = Collections.synchronizedSet(new HashSet<>());


总结

1.特点:无序,去重,非线程安全;

2.底层:HashMap的Key值实现的;

3.map.put方法,静态常量PRESENT,新值替换旧值;

4.map.remove key方法,如果KEY不存在时,则返回的是null,如果KEY存在时,返回的就是e.value,即PRESENT,返回true成功,返回false不成功;

5.去重原理:先判断hash值,再通过==或者equals判断,整体如果返回true,则为重复元素;

6.无序的则采用HashSet ,有序的则采用TreeSet;

7.线程安全的set:Collections.synchronizedSet(new HashSet<>());

相关推荐
鸽鸽程序猿5 分钟前
【前端】javaScript
开发语言·前端·javascript
kylin王国12 分钟前
R语言p值矫正整的方法
开发语言·r语言·p值
捂月28 分钟前
Spring Boot 核心逻辑与工作原理详解
java·spring boot·后端
凯子坚持 c29 分钟前
C++之二叉搜索树:高效与美的极致平衡
开发语言·c++
埋头编程~30 分钟前
【C++】踏上C++学习之旅(十):深入“类和对象“世界,掌握编程黄金法则(五)(最终篇,内含初始化列表、静态成员、友元以及内部类等等)
java·c++·学习
菜鸟起航ing43 分钟前
Java中日志采集框架-JUL、Slf4j、Log4j、Logstash
java·开发语言·log4j·logback
Nightselfhurt1 小时前
RPC学习
java·spring boot·后端·spring·rpc
苹果醋31 小时前
vue3 在哪些方便做了性能提升?
java·运维·spring boot·mysql·nginx
凤枭香1 小时前
Python Scikit-learn简介(二)
开发语言·python·机器学习·scikit-learn
孔汤姆1 小时前
部署实战(二)--修改jar中的文件并重新打包成jar文件
java·pycharm·jar