第一轮面试 面试官:先从基础的Java核心知识问起。Java中多态是如何实现的? 王铁牛:多态嘛,就是一个对象多种形态。通过继承、重写方法,还有父类引用指向子类对象来实现。 面试官:回答得不错。那HashMap在JDK1.7和JDK1.8中有什么主要区别? 王铁牛:1.7是数组加链表,1.8变成了数组加链表再加红黑树,当链表长度超过8就转红黑树。 面试官:很好。ArrayList和LinkedList在性能上有什么区别? 王铁牛:ArrayList随机访问快,因为是数组结构;LinkedList插入删除快,因为是链表结构。
第二轮面试 面试官:接下来聊聊JUC和多线程。线程池的核心参数有哪些,分别有什么作用? 王铁牛:嗯……有核心线程数、最大线程数,还有队列容量。核心线程数就是一开始创建的线程数,最大线程数就是最多能创建的线程数,队列容量就是存放任务的队列大小。 面试官:那线程池的拒绝策略有哪些? 王铁牛:有AbortPolicy,直接抛出异常;还有CallerRunsPolicy,把任务回退给调用者执行。 面试官:JVM的内存模型了解吗,简单说说。 王铁牛:JVM内存模型嘛,就是分堆、栈这些区域,堆是存放对象的,栈是存放局部变量这些的。
第三轮面试 面试官:谈谈Spring和Spring Boot。Spring的IOC和AOP是什么? 王铁牛:IOC就是控制反转,把对象创建和管理交给Spring容器。AOP是面向切面编程,能在不修改代码的情况下增加功能,像日志记录这些。 面试官:Spring Boot有什么优势,相比Spring? 王铁牛:Spring Boot自动配置,能快速搭建项目,减少配置文件,开发更方便。 面试官:MyBatis、Dubbo、RabbitMQ、xxl - job、Redis这些,说说MyBatis的一级缓存和二级缓存。 王铁牛:一级缓存是SqlSession级别的,在一个SqlSession内查询相同数据会从缓存取。二级缓存是mapper级别的,多个SqlSession都能用。
面试官:今天的面试就到这里,你回去等通知吧。我们会综合评估你的表现,无论结果如何,都会尽快给你回复。感谢你今天来参加面试。
问题答案:
- Java中多态是如何实现的:多态通过继承、方法重写和父类引用指向子类对象来实现。继承是多态的基础,子类继承父类获得其属性和方法。方法重写是子类对父类方法进行重新定义,以满足自身需求。父类引用指向子类对象,使得在运行时根据实际对象类型调用相应的方法。例如,父类Animal有一个方法eat(),子类Dog和Cat继承Animal并重写eat()方法,当使用Animal animal = new Dog()创建对象时,调用animal.eat()实际执行的是Dog类的eat()方法。
- HashMap在JDK1.7和JDK1.8中有什么主要区别:JDK1.7中HashMap采用数组加链表的数据结构。当发生哈希冲突时,新元素以头插法插入链表。这种结构在哈希冲突严重时,链表长度过长,查询性能会下降到O(n)。JDK1.8中,HashMap在数组加链表基础上,当链表长度超过8且数组容量大于64时,链表会转换为红黑树,查询性能提升到O(logn)。同时,JDK1.8采用尾插法插入新元素,避免了JDK1.7在多线程环境下头插法可能导致的链表成环问题。
- ArrayList和LinkedList在性能上有什么区别:ArrayList基于数组实现,支持随机访问,因为可以通过数组下标直接定位元素,时间复杂度为O(1)。但在插入和删除元素时,尤其是在数组中间位置操作,需要移动大量元素,时间复杂度为O(n)。LinkedList基于双向链表实现,插入和删除元素只需修改链表节点的指针,时间复杂度为O(1),但随机访问时需要从头或尾遍历链表,时间复杂度为O(n)。
- 线程池的核心参数有哪些,分别有什么作用:核心线程数(corePoolSize):线程池在正常情况下保持的线程数,即使这些线程处于空闲状态也不会被销毁。最大线程数(maximumPoolSize):线程池允许创建的最大线程数。当任务队列已满且活动线程数小于最大线程数时,线程池会创建新线程来处理任务。队列容量(workQueue):用于存放等待执行任务的队列。常用的队列类型有ArrayBlockingQueue(有界数组队列)、LinkedBlockingQueue(无界链表队列)等。
- 线程池的拒绝策略有哪些:AbortPolicy:这是默认的拒绝策略,当任务无法提交到线程池(队列已满且线程数达到最大线程数)时,直接抛出RejectedExecutionException异常。CallerRunsPolicy:当任务被拒绝时,将任务回退给调用者,由调用者所在线程执行该任务。这样可以降低新任务的提交速度,减轻线程池的压力。DiscardPolicy:直接丢弃被拒绝的任务,不做任何处理。DiscardOldestPolicy:丢弃队列中最老的任务(队头任务),然后尝试将新任务加入队列。
- JVM的内存模型了解吗,简单说说:JVM内存模型主要分为堆(Heap)、栈(Stack)、方法区(Method Area)等区域。堆是JVM中最大的一块内存区域,用于存放对象实例,所有线程共享。堆又可以细分为新生代和老年代,新生代用于存放新创建的对象,经过多次垃圾回收后依然存活的对象会进入老年代。栈是线程私有的,每个线程在创建时都会创建一个栈,用于存放局部变量表、操作数栈、动态链接、方法出口等信息。方法区用于存放类信息、常量、静态变量等数据,也是所有线程共享的。
- Spring的IOC和AOP是什么:IOC(Inversion of Control)即控制反转,是Spring的核心思想之一。传统开发中,对象的创建和管理由应用程序自身负责,而在Spring中,将对象的创建、初始化、销毁等控制权交给Spring容器,实现了对象控制权的反转。这样可以降低组件之间的耦合度,提高代码的可维护性和可测试性。AOP(Aspect - Oriented Programming)即面向切面编程,它将一些与业务逻辑无关但又贯穿多个业务模块的功能(如日志记录、事务管理、权限控制等)抽取出来,形成一个独立的切面,在不修改原有业务代码的情况下,通过动态代理等技术将这些切面功能织入到目标业务逻辑中,实现功能的复用和代码的解耦。
- Spring Boot有什么优势,相比Spring:Spring Boot最大的优势在于其自动配置功能。Spring框架在使用时需要大量的XML配置文件或Java配置类来配置各种组件,如数据源、事务管理器等,配置过程繁琐且容易出错。Spring Boot通过约定大于配置的原则,根据项目依赖自动配置Spring应用,极大地减少了配置文件的编写,开发者只需关注业务逻辑。同时,Spring Boot内置了Tomcat、Jetty等服务器,可直接打包成可执行的jar或war文件,方便部署。它还提供了一系列的starter依赖,简化了项目依赖管理。
- MyBatis的一级缓存和二级缓存:MyBatis的一级缓存是SqlSession级别的缓存。在同一个SqlSession内,MyBatis会缓存查询结果。当执行相同的SQL查询时,MyBatis首先会从一级缓存中查找,如果存在则直接返回缓存结果,不再执行SQL语句。一级缓存的生命周期与SqlSession一致,当SqlSession关闭或提交事务时,一级缓存会被清空。二级缓存是mapper级别的缓存,多个SqlSession可以共享二级缓存。MyBatis默认不开启二级缓存,需要在mapper.xml文件中配置开启。二级缓存的作用域是整个mapper的namespace,当一个SqlSession查询数据时,首先会查找一级缓存,若没有则查找二级缓存。二级缓存的实现依赖于Cache接口,MyBatis提供了多种缓存实现,如Ehcache、Redis等,开发者也可以自定义缓存实现。