热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java面试汇总(二)

8、拉链法导致的链表过深问题为什么不用二叉查找树代替,而选择红黑树?为什么不一直使用红黑树?之所以选择红黑树是为了解决二叉查找树的缺陷&#

8、拉链法导致的链表过深问题为什么不用二叉查找树代替,而选择红黑树?为什么不一直使用红黑树?
之所以选择红黑树是为了解决二叉查找树的缺陷,二叉查找树在特殊情况下会变成一条线性结构(这就跟原来使用链表结构一样了,造成很深的问题),遍历查找会非常慢。而红黑树在插入新数据后可能需要通过左旋,右旋、变色这些操作来保持平衡,引入红黑树就是为了查找数据快,解决链表查询深度的问题,我们知道红黑树属于平衡二叉树,但是为了保持“平衡”是需要付出代价的,但是该代价所损耗的资源要比遍历线性链表要少,所以当长度大于8的时候,会使用红黑树,如果链表长度很短的话,根本不需要引入红黑树,引入反而会慢。

9、 说说你对红黑树的见解?
在这里插入图片描述
1、每个节点非红即黑
2、根节点总是黑色的
3、如果节点是红色的,则它的子节点必须是黑色的(反之不一定)
4、每个叶子节点都是黑色的空节点(NIL节点)
5、从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)

10、解决hash 碰撞还有那些办法?
开放定址法。
当冲突发生时,使用某种探查技术在散列表中形成一个探查(测)序列。沿此序列逐个单元地查找,直到找到给定的地址。
按照形成探查序列的方法不同,可将开放定址法区分为线性探查法、二次探查法、双重散列法等。
下面给一个线性探查法的例子  
问题:已知一组关键字为(26,36,41,38,44,15,68,12,06,51),用除余法构造散列函数,用线性探查法解决冲突构造这组关键字的散列表。
解答:为了减少冲突,通常令装填因子α由除余法因子是13的散列函数计算出的上述关键字序列的散列地址为(0,10,2,12,5,2,3,12,6,12)。
前5个关键字插入时,其相应的地址均为开放地址,故将它们直接插入T[0],T[10),T[2],T[12]和T[5]中。
当插入第6个关键字15时,其散列地址2(即h(15)=15%13=2)已被关键字41(15和41互为同义词)占用。故探查h1=(2+1)%13=3,此地址开放,所以将15放入T[3]中。
当插入第7个关键字68时,其散列地址3已被非同义词15先占用,故将其插入到T[4]中。
当插入第8个关键字12时,散列地址12已被同义词38占用,故探查hl=(12+1)%13=0,而T[0]亦被26占用,再探查h2=(12+2)%13=1,此地址开放,可将12插入其中。

类似地,第9个关键字06直接插入T[6]中;而最后一个关键字51插人时,因探查的地址12,0,1,…,6均非空,故51插入T[7]中。

11、如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?

默认的负载因子大小为0.75&#xff0c;也就是说&#xff0c;当一个map填满了75%的bucket时候&#xff0c;和其它集合类(如ArrayList等)一样&#xff0c;将会创建原来HashMap大小的两倍的bucket数组&#xff0c;来重新调整map的大小&#xff0c;并将原来的对象放入新的bucket数组中。这个过程叫作rehashing&#xff0c;因为它调用hash方法找到新的bucket位置。这个值只可能在两个地方&#xff0c;一个是原下标的位置&#xff0c;另一种是在下标为<原下标&#43;原容量>的位置

12、重新调整HashMap大小存在什么问题吗&#xff1f;
当重新调整HashMap大小的时候&#xff0c;确实存在条件竞争&#xff0c;因为如果两个线程都发现HashMap需要重新调整大小了&#xff0c;它们会同时试着调整大小。在调整大小的过程中&#xff0c;存储在链表中的元素的次序会反过来&#xff0c;因为移动到新的bucket位置的时候&#xff0c;HashMap并不会将元素放在链表的尾部&#xff0c;而是放在头部&#xff0c;这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了&#xff0c;那么就死循环了。(多线程的环境下不使用HashMap&#xff09;
为什么多线程会导致死循环&#xff0c;它是怎么发生的&#xff1f;
HashMap的容量是有限的。当经过多次元素插入&#xff0c;使得HashMap达到一定饱和度时&#xff0c;Key映射位置发生冲突的几率会逐渐提高。这时候&#xff0c;HashMap需要扩展它的长度&#xff0c;也就是进行Resize。1.扩容&#xff1a;创建一个新的Entry空数组&#xff0c;长度是原数组的2倍。2.ReHash&#xff1a;遍历原Entry数组&#xff0c;把所有的Entry重新Hash到新数组。
&#xff08;这个过程比较烧脑&#xff0c;暂不作流程图演示&#xff0c;有兴趣去看看我的另一篇博文"HashMap扩容全过程"&#xff09;
达摩&#xff1a;哎呦&#xff0c;小老弟不错嘛~~意料之外呀
小鲁班&#xff1a;嘿嘿&#xff0c;优秀吧&#xff0c;中场休息一波&#xff0c;我先喝口水
达摩&#xff1a;不仅仅是这些哦&#xff0c;面试官还会问你相关的集合类对比&#xff0c;比如&#xff1a;

13、HashTable
数组 &#43; 链表方式存储
默认容量&#xff1a; 11(质数 为宜)
put:


  • 索引计算 : &#xff08;key.hashCode() & 0x7FFFFFFF&#xff09;% table.length
    若在链表中找到了&#xff0c;则替换旧值&#xff0c;若未找到则继续
    当总元素个数超过容量*加载因子时&#xff0c;扩容为原来 2 倍并重新散列。
    将新元素加到链表头部
    对修改 Hashtable 内部共享数据的方法添加了 synchronized&#xff0c;保证线程安全。

14、HashMap &#xff0c;HashTable 区别
默认容量不同。扩容不同
线程安全性&#xff0c;HashTable 安全
效率不同 HashTable 要慢因为加锁
15、ConcurrentHashMap 原理
1、最大特点是引入了 CAS&#xff08;借助 Unsafe 来实现【native code】&#xff09;
CAS有3个操作数&#xff0c;内存值V&#xff0c;旧的预期值A&#xff0c;要修改的新值B。当且仅当预期值A和内存值V相同时&#xff0c;将内存值V修改为B&#xff0c;否则什么都不做。
Unsafe 借助 CPU 指令 cmpxchg 来实现
使用实例&#xff1a;


1、对 sizeCtl 的控制都是用 CAS 来实现的 1、sizeCtl &#xff1a;默认为0&#xff0c;用来控制 table 的初始化和扩容操作。
-1 代表table正在初始化 N 表示有 -N-1 个线程正在进行扩容操作 如果table未初始化&#xff0c;表示table需要初始化的大小。 如果table初始化完成&#xff0c;表示table的容量&#xff0c;默认是table大小的0.75倍&#xff0c;居然用这个公式算0.75&#xff08;n - (n >>> 2)&#xff09;。
CAS 会出现的问题&#xff1a;ABA
对变量增加一个版本号&#xff0c;每次修改&#xff0c;版本号加 1&#xff0c;比较的时候比较版本号。


16、我们可以使用CocurrentHashMap来代替Hashtable吗&#xff1f;

我们知道Hashtable是synchronized的&#xff0c;但是ConcurrentHashMap同步性能更好&#xff0c;因为它仅仅根据同步级别对map的一部分进行上锁。ConcurrentHashMap当然可以代替HashTable&#xff0c;但是HashTable提供更强的线程安全性。它们都可以用于多线程的环境&#xff0c;但是当Hashtable的大小增加到一定的时候&#xff0c;性能会急剧下降&#xff0c;因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation)&#xff0c;不论它变得多么大&#xff0c;仅仅需要锁定map的某个部分&#xff0c;而其它的线程不需要等到迭代完成才能访问map。简而言之&#xff0c;在迭代的过程中&#xff0c;ConcurrentHashMap仅仅锁定map的某个部分&#xff0c;而Hashtable则会锁定整个map。
此时躺着床上的张飞哄了一声&#xff1a;睡觉了睡觉了~

见此不太妙&#xff1a;小鲁班立马回到床上&#xff08;泉水&#xff09;&#xff0c;把被子盖过头&#xff0c;心里有一丝丝愉悦感&#xff0c;不对。好像还没洗澡。。。

by the way
CocurrentHashMap在JAVA8中存在一个bug&#xff0c;会进入死循环&#xff0c;原因是递归创建ConcurrentHashMap 对象&#xff0c;但是在1.9已经修复了,场景重现如下

public class ConcurrentHashMapDemo{private Map cache &#61;new ConcurrentHashMap<>(15);public static void main(String[]args){ConcurrentHashMapDemo ch &#61; new ConcurrentHashMapDemo();System.out.println(ch.fibonaacci(80));}public int fibonaacci(Integer i){if(i&#61;&#61;0||i &#61;&#61;1) {return i;}return cache.computeIfAbsent(i,(key) -> {System.out.println("fibonaacci : "&#43;key);return fibonaacci(key -1)&#43;fibonaacci(key - 2);});}
}

推荐阅读
  • 本文深入解析了JDK 8中HashMap的源代码,重点探讨了put方法的工作机制及其内部参数的设定原理。HashMap允许键和值为null,但键为null的情况只能出现一次,因为null键在内部通过索引0进行存储。文章详细分析了capacity(容量)、size(大小)、loadFactor(加载因子)以及红黑树转换阈值的设定原则,帮助读者更好地理解HashMap的高效实现和性能优化策略。 ... [详细]
  • 面试题总结_2019年全网最热门的123个Java并发面试题总结
    面试题总结_2019年全网最热门的123个Java并发面试题总结 ... [详细]
  • 本文总结了Java初学者需要掌握的六大核心知识点,帮助你更好地理解和应用Java编程。无论你是刚刚入门还是希望巩固基础,这些知识点都是必不可少的。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • Java高并发与多线程(二):线程的实现方式详解
    本文将深入探讨Java中线程的三种主要实现方式,包括继承Thread类、实现Runnable接口和实现Callable接口,并分析它们之间的异同及其应用场景。 ... [详细]
  • 深入解析Java虚拟机的内存分区与管理机制
    Java虚拟机的内存分区与管理机制复杂且精细。其中,某些内存区域在虚拟机启动时即创建并持续存在,而另一些则随用户线程的生命周期动态创建和销毁。例如,每个线程都拥有一个独立的程序计数器,确保线程切换后能够准确恢复到之前的执行位置。这种设计不仅提高了多线程环境下的执行效率,还增强了系统的稳定性和可靠性。 ... [详细]
  • 线程能否先以安全方式获取对象,再进行非安全发布? ... [详细]
  • 本文深入解析了Java 8并发编程中的`AtomicInteger`类,详细探讨了其源码实现和应用场景。`AtomicInteger`通过硬件级别的原子操作,确保了整型变量在多线程环境下的安全性和高效性,避免了传统加锁方式带来的性能开销。文章不仅剖析了`AtomicInteger`的内部机制,还结合实际案例展示了其在并发编程中的优势和使用技巧。 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 传统上,Java 的 String 类一直使用 char 数组来存储字符数据。然而,在 Java 9 及更高版本中,String 类的内部实现改为使用 byte 数组。本文将探讨这一变化的原因及其带来的好处。 ... [详细]
  • 兆芯X86 CPU架构的演进与现状(国产CPU系列)
    本文详细介绍了兆芯X86 CPU架构的发展历程,从公司成立背景到关键技术授权,再到具体芯片架构的演进,全面解析了兆芯在国产CPU领域的贡献与挑战。 ... [详细]
  • javax.mail.search.BodyTerm.matchPart()方法的使用及代码示例 ... [详细]
  • MySQL 5.7 学习指南:SQLyog 中的主键、列属性和数据类型
    本文介绍了 MySQL 5.7 中主键(Primary Key)和自增(Auto-Increment)的概念,以及如何在 SQLyog 中设置这些属性。同时,还探讨了数据类型的分类和选择,以及列属性的设置方法。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • 在使用SSH框架进行项目开发时,经常会遇到一些常见的问题。例如,在Spring配置文件中配置AOP事务声明后,进行单元测试时可能会出现“No Hibernate Session bound to thread”的错误。本文将详细探讨这一问题的原因,并提供有效的解决方案,帮助开发者顺利解决此类问题。 ... [详细]
author-avatar
福州-台江_616
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有