Java面试中出现的那些高频问题

1. 说一说HashMap的原理?

答案:底层通过数组+链表的结构去维护一个Entry,每次put元素时,会调用hashcode()方法确认元素在数组中的下标位置,如果该位置没有元素,直接插入,已经有元素存在,继续调用equals()方法对比2个元素是否相等,相等则新的元素覆盖旧的元素,不相等的话会以这个数组下标为起点,插入到链表的节点中。默认容量是16,负载因子0.75(负载因子就是说容量为16,但是不会真正存到16个元素才会触发扩容,扩容的起点是16*0.75,也就是存储到第12个元素的时候就会扩容,不然装不下了啊兄弟。),默认扩容2倍。

2.jdk1.8中的hashmap相比1.7中做了哪些优化?

答案:头插法改成了尾插法,避免了死锁。

2.1 为什么HashMap的负载因子是0.75?0.8不行吗?

答案:一种折中的方案吧,哈希表分布的更均匀,不会因为频繁的哈希冲突触发扩容。

3.HashMap中的链表什么情况下转换成红黑树?什么时候从红黑树再转回链表结构,为什么?

答案:数组长度大于64并且链表长度大于8时,会转换为红黑树;节点小于6时,会再次退化为链表。为啥不干脆用红黑树算了,变来变去的不浪费性能吗?这肯定不行,数据量不大的时候数组+链表的结构效率是高于红黑树的,并且红黑树进行左旋、右旋和变色的时候会消耗更多的资源。

4.HashMap和ConcurrentHashMap的区别,说一说ConcurrentHashMap的实现原理。

答案:HashMap是线程不安全的。(这里说一下到底什么是线程不安全?有个前提,就是必须在多线程环境下,单线程没有任何意义,所谓的不安全就是多线程操作会造成数据错误!!)在多线程环境中会造成数据错误(jdk1.7中主要是头插法的原因造成,1.8修改成了尾插法,但是1.8版本的hashmap还是不安全,多线程环境下会造成数据覆盖);ConcurrentHashMap是线程安全的。jdk1.7中通过segement分段锁保证每次加锁只锁住一段数据,提高了并发量。1.8进行了优化使用CAS+Synchorinize。

4.1 了解CopyonwriteArrayList吗?

答案:这是一个在进行写操作时对集合进行复制的容器,写操作不会在原来的容器上进行,而是将原来的容器复制一份出来,在这个新复制的容器中进行修改,修改完成以后将原容器的引用指向这个修改过后的新的ArrayList。适用场景:读多写少的时候。

4.2  Synchonized,ReentrentLock这些也是面试常问的点,不了解锁机制,你就不了解多线程是怎么回事,推荐有时间的熟读下《深入了解JVM原理》《并发编程的艺术》。

5.看你写熟悉MYSQL,那你说说了解哪些数据库锁吧。

答案:表锁(代表就是MYISAM引擎),行锁(INNODB引擎,这里锁住的不是数据库的行记录,而是索引),全局锁。

5.1 你都了解哪些MYSQL存储引擎?

答案:MEMORY  MYISAM  INNODB  ARCHIVE这几个是比较常见的。

6.乐观锁和悲观锁有啥区别?对应的应用场景。

答案:区别就是悲观锁会完全锁住数据,同时只让一个线程去访问,其他线程都会阻塞;乐观锁是每次认为不会有并发操作产生,到进行最后写操作时会对比版本号,如果版本号发生变化则修改失败(表里手动添加Version字段)。

7.哦,你还有SQL调优经验,那你说说平时工作中都是怎么调的?

答案:explain都会用吧?不会用的百度下,根据提示进行针对性调优。推荐《MYSQL必知必会》

8.索引是不是越多越好,为什么?

答案:不是,索引的本质其实也是表,创建索引需要占用磁盘空间,而且每次对db进行增删改操作时都需要重新维护索引。

9.你们是如何处理海量数据的?(回答用中间件去分库分表)此时面试官一定会追问:假设现在有一张存储了海量数据的表,你打算如何拆分?

答案:其实没有标准答案,要根据实际业务情况去拆分。一般情况下会先对表中的字段进行拆分,也就是所谓的分表,把原来放在一张表里的多个业务字段根据业务内容拆分出来形成多个表,从而减轻数据库的压力。如果分表之后数据库访问压力还是大,建议分库,分库有2种,一是垂直拆分,二是水平拆分。垂直拆分和分表其实差不多,只不过拆分后的单位是库,水平拆分需要根据数据库行记录进行分割,例如用户量短期内暴增的话,可以根据用户的id%2的结果(奇数或偶数)进行行记录拆分,id是奇数的保存到a数据库,id是偶数的保存到b数据库。这里拆分方式只是举个例子,实际业务中的拆分方式多种多样,这个只作为参考。

9.1 你都了解哪些分库分表中间件?

答案:sharding-jdbc(现在是主流)  mycat(社区活跃度不行)。

10.MYSQL索引是怎么实现的?

答案:那肯定是通过数据结构了,所以学好数据结构还是很重要的。通常我们都是使用B+tree去维护索引,因为hash索引是不支持范围查找的,对于精确查找来说hash索引是个好的选择,不过现在的业务来说,几乎没有不搞范围查找的吧。。至于Btree,性能各方面都不如B+tree,看名字应该也知道B+是对B的变种或者说是升级。

11.了解二叉树的结构吗,说说原理。

答案:这个自己去看看数据结构把,一句两句讲不清楚。

12.说说单例模式有几种写法。

答案:饿汉式  懒汉式  双重检索 枚举  内部类,说完最好说下有哪些是线程安全的,只有内部类的形式是不安全的(可以通过反射破坏单例),其他都可以通过加锁解决。

13.threadlocal用过吗?能说一下原理吗?

答案:说简单点就是保存了一份线程内部的变量,通过threadlocalMap维护了一个entry,key是threadLocal,value是它的值,就这么简单。注意它有个坑,使用完别忘了remove,否则会内存泄漏,因为threadLocal是弱引用,gc线程一旦启动会直接把key回收掉,而value是强引用,会长时间停留在内存中。

14.那你再说说jvm的内存结构吧,(注意是内存结构不是内存模型)

答案:分为栈空间、堆空间、方法区、native本地方法区,还有一个引用计数器。这里最好回答下jdk1.7和1.8中的区别,显得我们懂得多一点,加点分,哈哈。

15.双亲委派机制了解吗?收到类加载请求的加载器自己不能首先去加载吗?为什么?

答案:当一个加载器收到类加载请求时,它不会自己去加载,而是交给它的父类去加载。如果它自己加载的话,我们自己也有个和String类同名同包的类,这不是乱套了吗。

16.什么情况下对象会被垃圾回收器回收?

答案:确认对象到GCROOTS之间没有任何引用链的时候,会被认为是可回收对象。但是不会立马被回收,接下来会去查看对象有没有覆盖finalize()方法,如果没有覆盖过,那么这个对象会被判死刑,必定被回收;如果覆盖过finalize()方法的话,此时只要该对象与被视为GCRoots的引用重新建立连接,就会逃过本次GC。

17.你了解哪些GC算法?

答案:标记清除(会产生大量不连续的内存空间,假设下一次要分配一个大对象,就没有足够的连续空间给他用了,老年代就需要进行一次majorGC)  标记整理(改进了标记清除的不足) 复制(就是把内存分成2块用,一块用完了进行GC后,存活的对象移动到另一块上,周而复始..)   分代收集(一般是年轻代用复制算法,老年代用标记整理)。说完最好回答下各自的优缺点-就是括号里那些东西,毕竟我们不能和面试官说 懂的都懂。。O(∩_∩)O哈哈~

<!-- 框架部分 -->

我:这个面试官问题有点多啊。。

18.什么是IOC容器?

答案:生产bean的容器,以前程序员需要手动new对象,现在创建对象的任务交给spring(通过xml文件或者注解都可以)。

19.spring中bean的生命周期。

答案:这个说起来很长,可以自己去了解下,简单说说即可。

20.spring框架用到了哪些设计模式?

答案:工厂模式(IOC)、代理模式(AOP)、模板模式(各种封装好的template)、策略模式(Resource类)、适配器模式(AOP的Advice通知就用到了转换接口)以及观察者模式。

21.scope注解都有哪些属性?

答案:有5种,singleton  protype request session  globalSession。

22.aop你了解吗?都有哪些实现方式?各自有什么区别?

答案:基于jdk动态代理和cglib。前者必须要实现接口,后者通过修改字节码生成被代理类的子类。

PS:面试官:这小伙子不错啊,没想到能坚持这么久。

废话,不背个几天面试题我敢来吗~

23.那你再说说MYBATIS的一级缓存和二级缓存吧,以及什么时候会失效。

答案:一级缓存是sqlSession级别的,mybatis默认开启,数据不共享;二级缓存是namespace级别的,数据是共享的,需要手动开启;两者的共同点是进行增、删、改操作后,缓存都会被清除。

24.能再说说MYBATIS的运行过程吗?

这个我还没背过,不好意思哈面试官...

25.MYBATIS中拦截器的实现原理了解不?

27.SpringMVC的运行原理?

28.SpringMVC有哪些常用注解?

答案:@Controller  @ExceptionHandler  @ResponseBody  @RequestBody  @RequestMapping  @RequestParam等等...,相信你说出这几个以后,面试官也不会继续问了。

29.SpringMVC和Spring Boot的区别?

答案:SpringMVC是mvc框架,应用于表现层,Springboot是简化spring框架各种繁琐配置的一个升级版本,严格意义上不能说它是框架。

30.你能说清楚Spring Boot自动配置的原理吗?

答案:说来话长,一切从@SpringBootApplication这个注解开始开启吧,内置了componentscan和autoConfiguration注解,自己可以去看下,这里就不细说了,不过看过很多博客没有一个人能用很简短的话语去描述的,都是长篇大论,看了头疼。

31.spring是如何解决循环依赖的?

答案:通过三级缓存(三级缓存的知识点可以自己去了解下),并且只能解决属性依赖,构造函数级别的循环依赖目前无法解决(平时做项目也尽量避免这些骚操作)。

32.假如你写了一段代码正好引发了循环依赖问题,你怎么解决?

答案:在其中一个bean上引入@Lazy注解,被该注解注释后bean会延迟加载,完美解决!

33.平时工作中,你是如何解决重复提交和幂等的?

答:前端可以设置按钮点击后就禁用一段时间(比如60s),或者引入验证码。

       后端:数据库唯一索引 + token防重(每次请求前申请一个token存入redis中,请求完成后删除token,这样下次请求进来get一下还存在token视为重复请求,注意删除token时要判断是否删除成功,否则在多线程环境下还是会存在问题)。

34.了解事务吗?说说都有哪些特性?

答:事务就是一系列不可再分割的原子操作(要么全部成功,要么全部失败,不存在中间状态)。事务有4大特性:原子性、一致性、持久性、隔离性。4个特性可以再详细说说。

35.那你说的这些特性在数据库层面(Mysql)是如何实现的?

答:原子性通过undolog实现,事务提交失败时通过undolog回滚数据。

       持久性通过redolog来保证,事务提交时先写入redolog,在合适的时机刷盘,这样就算db宕机了,也能通过redolog恢复。

      隔离性通过加锁的方式解决。

      最后的一致性是通过以上3个特性来实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值