第一轮面试 面试官:先来聊聊Java基础,讲讲Java中基本数据类型有哪些? 王铁牛:基本数据类型有整型,像byte、short、int、long,还有浮点型float、double,字符型char,布尔型boolean。 面试官:不错,回答得很准确。那自动装箱和拆箱是怎么回事? 王铁牛:自动装箱就是把基本数据类型转为包装类型,比如int转Integer;拆箱就是反过来,包装类型转基本数据类型。 面试官:很好。ArrayList和HashMap在存储原理上有什么不同? 王铁牛:ArrayList是顺序存储,按顺序存元素;HashMap是基于哈希表,通过哈希值来存和取元素。
第二轮面试 面试官:接下来谈谈多线程和JUC。线程池有哪些核心参数? 王铁牛:有核心线程数、最大线程数、存活时间、时间单位,还有阻塞队列。 面试官:那说说线程池的工作流程,当任务提交时,线程池是怎么处理的? 王铁牛:嗯……就是先看核心线程有没有满,满了就放队列里,队列满了再看最大线程数,要是都满了就执行拒绝策略。 面试官:还行,表述基本正确。那在高并发场景下,HashMap会出现什么问题? 王铁牛:呃……可能会有线程安全问题,多个线程操作可能数据会乱。
第三轮面试 面试官:聊聊框架相关,Spring的IOC和AOP是什么? 王铁牛:IOC是控制反转,把对象创建和管理交给Spring容器;AOP是面向切面编程,能在不修改代码的情况下增加功能。 面试官:Spring Boot有什么优势,相比传统Spring项目? 王铁牛:它简化了配置,能快速搭建项目,内置了很多插件,开发更方便。 面试官:那Dubbo在分布式系统中有什么作用? 王铁牛:它是个分布式服务框架,能做服务治理,像服务注册、发现这些。
面试总结:从这三轮面试来看,你对于一些基础的Java知识掌握得还可以,像基本数据类型、自动装箱拆箱,以及ArrayList和HashMap的存储原理都回答得不错。在多线程和JUC方面,线程池的核心参数和工作流程也表述得较为清晰。不过,对于一些稍微复杂点的问题,比如高并发下HashMap的问题,回答得还不够深入。在框架方面,Spring的IOC和AOP,以及Spring Boot的优势都能说个大概,但对于Dubbo在分布式系统中的作用,阐述得还不够全面。整体而言,你有一定的知识储备,但在技术的深度和广度上还有提升空间。今天的面试就到这里,你回去等我们的通知吧。
问题答案:
- Java基本数据类型:Java有8种基本数据类型,整型(byte:8位,取值范围 -128 到 127;short:16位,取值范围 -32768 到 32767;int:32位;long:64位),浮点型(float:单精度,32位;double:双精度,64位),字符型(char:16位,用于存储单个字符),布尔型(boolean:只有true和false两个值)。这些基本数据类型是Java语言的基础,它们在内存中占用固定大小的空间,与包装类型相比,操作效率更高。
- 自动装箱和拆箱:自动装箱是Java编译器在编译期自动将基本数据类型转换为对应的包装类型,例如
int i = 10; Integer integer = i;这里编译器会自动调用Integer.valueOf(i)方法完成装箱。自动拆箱则相反,是将包装类型转换为基本数据类型,如Integer integer = 10; int i = integer;编译器会自动调用integer.intValue()方法。这一机制使得基本数据类型和包装类型之间的转换更加便捷,在很多场景下无需手动转换。 - ArrayList和HashMap存储原理:ArrayList是基于数组实现的动态数组,它按顺序存储元素,在内存中是连续存储的。当添加元素时,如果数组容量不足,会进行扩容。它适合按顺序访问元素的场景,查询效率高,但插入和删除元素(非尾部)时,需要移动元素,效率较低。HashMap基于哈希表实现,它通过对键进行哈希运算得到哈希值,根据哈希值确定元素在哈希表中的存储位置。哈希表由数组和链表(JDK1.8后引入红黑树优化)组成,当哈希冲突发生时,会将冲突的元素以链表或红黑树的形式存储在同一位置。HashMap适合快速查找和插入操作,但遍历无序。
- 线程池核心参数:核心线程数(corePoolSize):线程池中保持存活的最小线程数,即使这些线程处于空闲状态也不会被销毁,除非设置了
allowCoreThreadTimeOut为true。最大线程数(maximumPoolSize):线程池允许创建的最大线程数。存活时间(keepAliveTime):当线程数大于核心线程数时,多余的空闲线程的存活时间,超过这个时间,多余线程会被销毁。时间单位(unit):存活时间的单位,如TimeUnit.SECONDS。阻塞队列(workQueue):用于存放等待执行的任务,常见的有ArrayBlockingQueue、LinkedBlockingQueue等。 - 线程池工作流程:当任务提交到线程池时,首先判断核心线程数是否已满,如果未满,创建新的核心线程来执行任务;如果核心线程已满,则将任务放入阻塞队列中。如果阻塞队列也已满,再判断当前线程数是否达到最大线程数,如果未达到,创建新的非核心线程来执行任务;如果达到最大线程数,就会执行拒绝策略,常见的拒绝策略有
AbortPolicy(直接抛出异常)、CallerRunsPolicy(由调用者线程执行任务)、DiscardPolicy(丢弃任务)、DiscardOldestPolicy(丢弃队列中最老的任务)。 - 高并发下HashMap问题:在高并发环境下,HashMap可能会出现线程安全问题。例如,在JDK1.7及之前,当多个线程同时进行扩容操作时,可能会形成环形链表,导致死循环。在JDK1.8中,虽然对HashMap进行了一些优化,如引入红黑树,但在多线程环境下,数据的读写操作仍可能出现数据不一致的情况。因为HashMap本身不是线程安全的,多个线程同时对其进行写操作时,可能会导致数据覆盖、丢失等问题。
- Spring的IOC和AOP:IOC(Inversion of Control)即控制反转,是Spring框架的核心概念之一。它将对象的创建和管理从应用程序代码中转移到Spring容器中,通过依赖注入(Dependency Injection)的方式,Spring容器负责创建对象、管理对象的生命周期以及对象之间的依赖关系。例如,一个类A依赖类B,在传统方式下,A类需要自己创建B类的实例,而在IOC模式下,Spring容器会创建B类实例并注入到A类中。AOP(Aspect - Oriented Programming)即面向切面编程,它是一种编程范式,旨在将横切关注点(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,形成独立的切面。通过在运行时将切面织入到目标对象的方法调用中,实现对业务逻辑的增强,而无需修改业务代码本身。例如,在方法执行前后添加日志记录,通过AOP可以很方便地实现。
- Spring Boot优势:相比传统Spring项目,Spring Boot极大地简化了配置。它采用了约定大于配置的原则,内置了大量的starter依赖,开发者只需引入相关的starter,Spring Boot就能自动配置好相关的组件,如数据库连接、Web服务器等,大大减少了手动配置的工作量。同时,Spring Boot能快速搭建项目,开箱即用,提高了开发效率。它还支持嵌入式Web服务器,如Tomcat、Jetty等,使得项目部署更加便捷,无需像传统Spring项目那样部署到独立的Web容器中。
- Dubbo在分布式系统中的作用:Dubbo是一款高性能的Java RPC(Remote Procedure Call)分布式服务框架。在分布式系统中,它主要用于服务治理。首先是服务注册与发现,Dubbo提供了注册中心(如Zookeeper),服务提供者将自己的服务注册到注册中心,服务消费者从注册中心获取服务提供者的地址信息,实现服务的动态发现。其次,Dubbo支持负载均衡,当有多个服务提供者时,它能根据不同的负载均衡策略(如随机、轮询、最少活跃调用数等)将请求合理分配到各个服务提供者上,提高系统的整体性能。此外,Dubbo还具备服务监控功能,能对服务的调用次数、调用时间等进行统计和监控,方便开发者了解系统的运行状况,进行性能调优。