注:源码系列文章主要是对某付费专栏的总结记录。如有侵权,请联系删除。
Map 在面试中,占据了很大一部分的面试题,其中以 HashMap 为主,这些面试题目有的可以说清楚,有的很难说清楚,如果是面对面面试的话,建议画一画。
答:HashMap 底层是 数组 + 链表 + 红黑树
的数据结构,数组的作用主要是方便快速查找,时间复杂度是 O(1),默认大小是 16,数组的下标索引是通过 Key 的 hash 计算出来的(index = (tab.length - 1) & hash
),数组元素叫做 Node,当多个 key 的 hashcode 一致,但 key 值不同时,就叫做(hash 碰撞冲突),单个 Node 就会转化成链表,链表的查询复杂度是 O(n),当链表的长度大于等于 8 并且数组大小(tab.length)超过 64 时,链表就会转化成红黑树,红黑树的查询复杂度是 O(log(n)),简单来说,最坏的查询次数相当于红黑树的最大深度。
答:
相同点:
ConcurrentModificationException
错误。不同点:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// index = (tab.length - 1) & hash
以上代码是 HashMap 的 hash 算法。
这其实是个数学问题,源码中就是通过以上代码来计算 hash 的,首先计算出 key 的 hashcode,因为 key 是 Object,所以会根据 key 的不同类型进行 hashcode 的计算,接着计算 h ^ (h >>> 16)
,这么做的好处是使大多数场景下,算出来的 hash 值比较分散。
一般来说,hash 值算出来之后,要计算当前 key 在数组中的索引下标位置,可以采用取模的方式,就是:索引下标位置 = hash 值 % 数组大小
,这样做的好处,就是可以保证计算出来的索引下标值可以均匀的分布在数组的各个索引位置上,但取模操作对于处理器的计算是比较慢的,数学上有个公式,当 b 是 2 的幂次方时
, a & b = a & (b - 1)
,所以此处索引位置的计算公式我们可以更改为:(n - 1) & hash
。
此问题可以延伸出三个小问题:
答:如果 key 是数字,直接用 key % 数组大小是没有问题的,但我们的 key 还有可能是字符串,是复杂对象,这时候用 字符串或复杂对象 % 数组大小是不行的,所以需要先计算出 key 的 hash 值。
答:hash 算法是 h ^ (h >>> 16)
,为了使计算出的 hash 值更分散,所以选择先将 h 无符号右移 16 位,然后再与 h 异或,就能达到 h 的高 16 位和低 16 位都能参与计算,减少了碰撞的可能性。
答:key.hashCode() 算出来的 hash 值还不是数组的索引下标,为了随机的计算出索引的下标位置,我们还会用 hash 值和数组大小进行取模,这样子计算出来的索引下标比较均匀分布。
取模操处理器计算比较慢,处理器对 & 操作就比较擅长,换成了 & 操作,是有数学证明的支撑,提高了处理器处理的速度。
答:因为只有大小是 2 的幂次方时,才能使 hash 值 % n(tab.length) == (n - 1) & hash 公式成立。
答:
网上列举的一些其它方法,尽量不要说,因为这些方法资料很少,实战用过的人更少,如果你没有深入研究的话,面试官让你深入描述一下很难说清楚,反而留下了不好的印象,说说 HashMap 现有的措施就足够了。
答:
扩容的时机:
resize() 中的 newCap = oldCap << 1
。(ArrayList 扩容为 1.5 倍(newCapacity = oldCapacity + (oldCapacity >> 1)
))扩容的门阀值是 threshold
,每次扩容时 threshold
都会被重新计算,门阀值等于 数组大小 * 影响因子(0.75)
。
新数组初始化之后,需要将老数组的值拷贝到新数组上,链表和红黑树都有自己的拷贝方法。
答:hash 冲突指定是 key 值的 hashcode 计算相同,但 key 值不同的情况。
如果桶中的元素原本只有一个或已经是链表了,新增元素直接追加到链表尾部;
如果桶中元素已经是链表,并且链表个数大于等于 8 时,此时有两种情况:
这里不仅仅判断了链表元素个数大于等于 8,还判断了数组大小,数组容量小于 64 没有立即转化的原因,猜测主要是因为红黑树占用的空间比链表大很多,转化也比较耗时,所以数组容量小的情况下冲突严重,我们可以先尝试扩容,看看能否通过扩容来解决冲突的问题。
答:当链表元素个数太多时,遍历可能比较耗时,转化成红黑树,可以使遍历的时间复杂度降低。但转化成红黑树,有空间和转化耗时的成本,我们通过 泊松分布公式
计算,正常情况下,链表个数出现 8 的几率不到千万分之一,所以说正常情况下,链表都不会转化成红黑树,这样设计的目的是为了防止非正常情况下,比如 hash 算法出问题时,导致链表元素个数轻易大于等于 8 时,仍然能够快速遍历。
延伸问题:红黑树什么时候转化成链表?
答:当节点的个数小于等于 6 时,红黑树会自动转化为链表,主要还是考虑红黑树的空间成本问题,当节点个数小于等于 6 时,遍历链表也很快,所以红黑树会重新变成链表。
答:如果数组有了 key,但不想覆盖 value,可以选择 putIfAbsent
方法,这个方法有给内置变量 onlyIfAbsent,内置是 true,就不会覆盖,我们平时使用的 put 方法,内置 onlyIfAbsent 为 false,是允许覆盖的。
取值时,如果为空,想返回默认值,可以使用 getOrDefault
方法,方法第一参数为 key,第二参数为你想返回的默认值,如 map.get(“10”, “3”),当 map 中没有 key 为 10 的值时,会返回默认值 3,而不是为空。
HashMap<String,String > map = Maps.newHashMap();
map.put("1","1");
map.put("2","2");
map.forEach((s, s2) -> map.remove("1"));
答:不行,会报 ConcurrentModificationException,如下:
@Override
public void forEach(BiConsumer<? super K, ? 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.key, e.value);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
发现 HashMap 重写了 Map 的 forEach 方法,会判断 modCount。建议使用迭代器的方式进行珊瑚,原理同 ArrayList 迭代器类似。
答:可以详细描述下源码的实现路径,说不清楚的话,可以画一画。
答:DTO 就是一个数据载体,可以看做拥有很多属性的 Java 类,我们可以对这些属性进行 get、set 操作。
看是什么类型的 Map。如果是 HashMap 的话,一定要覆写 equals 和 hashCode 方法,因为在 get、put 的时候,需要通过 equals 方法进行相等的判断;如果是 TreeMap 的话,DTO 需要实现 Comparable 接口,因为 TreeMap 会使用 Comparable 接口进行判断 key 的大小;如果是 LinkedHashMap 的话,和 HashMap 一样。
答:LRU,英文全称:Least recently used,中文叫做最近最少访问,在 LinkedHashMap 中,也叫做最少访问删除策略,我们可以通过 removeEldestEntry
方法设定一定的删除策略,使最少被访问的元素,在适当的时机被删除,原理是在 put 方法执行的最后,LinkedHashMap 会去检查这种策略,如果满足策略,就删除头节点。LinkedHashMap 覆写了 HashMap 的 afterNodeInsertion
方法。
保证头节点就是最少访问元素的原理是:LinkedHashMap 在 get 的时候,就会把当前访问的节点,移动到链表的尾部,慢慢的,就会使头部的节点成为最少被访问的元素。
答:因为 TreeMap 的底层就是通过排序来比较两个 key 的大小的,所以推荐 key 实现 Comparable 接口,是为了让 key 的排序往你希望的排序顺序上发展,而 String 本身已经实现了 Comparable 接口,所以使用 String 时,我们不需要额外的工作,不仅仅是 String,其它包装类型也都实现了 Comparable 接口,如 Long、Double、Float 等等。
Map 的面试题主要是 HashMap 为主,会问很多源码方面的问题,TreeMap 和 LinkedHashMap 主要以功能和场景为主,作为加分项。
Map 的面试题很多,但只要弄懂原理,题目再多变化,回答起来都会比较简单。
------------------------------------- END -------------------------------------
文章浏览阅读2.5k次,点赞23次,收藏44次。本文介绍了焊盘命名规范以及如何用Cadence Allegro 16.6制作表贴焊盘和通孔焊盘。_allegro表贴焊盘制作
文章浏览阅读4.1k次。1,在多线程中我们知道一个问题就是i++操作时,我们得到的结果和我们想象的结果不一样,因为i++操作会被分成三步。分别是取值,++操作,赋值(读,改,写)。当线程执行到取值或者++操作时,线程突然切换,所以最终得到的结果可能有些奇怪!看看下面程序创建是个线程对i进行++操作public class AtomicTest { public static void main(String[] a..._多线程 i++
文章浏览阅读629次。点击输出坐标系文本框右侧按钮,弹出空间参考属性对话框,依次点击投影坐标系->Gauss Kruger->CGCS2000->CGCS2000_3_Degree_GK_Zone_35,CGCS2000_3_Degree_GK_Zone_35代表3度带、高斯投影、代号为35度带,具体选择多少带号,根据经度值换算,具体换算方式自己网上查询(测绘人都知道)。在输出要素类处,选择输出数据的路径及名称,点击确定,在arcmap右侧内容列表中生成一个新的要素类,此步骤目的是将数据导出为shp文件。_经纬度 gis 成面
文章浏览阅读1w次,点赞2次,收藏3次。在cmd里输入cd myclass 提示系统找不到指定路径我刚学java的 其他回答 共 3 条如说:你用javac D:\myclass\Welcome.java成功编译了,那么 在D:\myclass下面会生成一个Welcome.class的文件,接着: 开始→运行→CMD 确定(打开DOS窗口) 把路径换回D:\myclass (操作如:C:\Docum_cmd cd系统找不到指定的路径
文章浏览阅读1.9k次,点赞5次,收藏3次。本系列文章主要对Bug类路径规划算法的原理进行介绍,在本系列的第一篇文章中按照时间顺序梳理了自1986年至2018年Bug类路径规划算法的发展,整理了13种BUG系列中的典型算法,从本系列的第二篇文章开始依次详细介绍了其中具有代表性的BUG1、BUG2、Tangent BUG、I-BUG、RandomBug、BugFlood等算法。_tangent bug代码详解
文章浏览阅读5.3k次。爬坑SalMap无法使用-r、-l命令问题原因解决方法背景原因示例sqlmap -r 读取HTTP POST数据包sqlmap -l 读取HTTP GET数据包解决方法http数据包没有请求参数信息,即没有携带注入点默认情况下请求连接为:http://192.168.138.20/Less-1/默认不带有请求参数信息的,需要我们手动添加?id=1还没有带有参数这个时候我们抓包获取http请求信息,sqlmap -r、-l是扫描不出来的,如下图所示:设置请求参数请求连接为:htt_specified file '1.txt' does not contain a usable http request (with paramete
文章浏览阅读66次。转自:http://blog.jobbole.com/96225/本文旨在帮助 C/C++ 程序员们了解链接器到底完成了些什么工作。多年来,我给许多同事解释过这一原理,因此我觉得是时候把它写下来了,这样不仅可以供更多人学习,也省去我一遍遍讲解。[2009年3月更新,内容包括:增加了 Windows 系统中链接过程可能遇到的特殊问题,以及对某条定义规则的澄清。]促使我写下这篇文章的起因是..._各部分的命名:看看 c 文件中都包含了哪些内容
文章浏览阅读2.5w次,点赞10次,收藏38次。Toolbar是什么Toolbar是Google在Android 5.0中推出的一款替代ActionBar的View。ActionBar必须得作为Activity内容的一部分,而Toolbar可以放在任何层次。Toolbar比ActionBar支持更多的功能,从开始到终点,Toolbar包含下面可选的元素: - 一个导航按钮。 可以是一个向前的按钮、导航菜单按钮,等等。 - 一个logo图片_如何美化app
文章浏览阅读1.2k次。C# Windows服务安装、卸载批处理代码_c# 安装服务批处理 -i pause
文章浏览阅读212次。“企业互联网信息门户网站解决方案经验谈” 非常感谢博文视点资讯有限公司(武汉)一如既往对武汉.NET俱乐部的支持。本次活动将于2007年1月6日举行。以下是沙龙的详细安排: 演讲主题:“企业互联网信息门户网站解决方案经验谈”主讲人简介:陈欣军武汉追梦信息产业有限公司 总经理...
文章浏览阅读5k次,点赞3次,收藏25次。Debian Linux配置网络环境。//有线网卡//无线网卡_linux 有线网卡无线网卡 路由设置
文章浏览阅读5.4k次,点赞14次,收藏111次。项目时间:2020年6月大专二年级的安卓课程设计项目亮点:2D可视化的编辑地图项目简要:管理员编辑图书馆楼层的2D地图,学生在图书馆2D地图上选座。用户管理:登录、注册、修改个人信息、更改头像 。楼层管理:添加、修改、编辑、删除楼层地图、保存为模板 。模板管理:修改、删除、生成为楼层地图 。选座管理:查询座位、我的座位、修改座位 。知识点:application+sqlite+canvas+碎片+re_android的图书馆座位预定系统可行性分析