第一轮面试 面试官:先来聊聊Java基础,说说Java中基本数据类型有哪些? 王铁牛:基本数据类型有整型,像byte、short、int、long,还有浮点型float、double,字符型char,布尔型boolean。 面试官:不错,回答得很准确。那自动装箱和拆箱是怎么回事? 王铁牛:自动装箱就是把基本数据类型转为包装类型,比如int转Integer;拆箱就是反过来,包装类型转基本数据类型。 面试官:很好。ArrayList和HashMap在存储结构上有什么区别? 王铁牛:ArrayList是基于数组的,有序存储;HashMap是基于哈希表,无序存储,通过键值对来存储数据。
第二轮面试 面试官:进入JUC相关问题。讲讲线程池的核心参数有哪些? 王铁牛:嗯……有核心线程数、最大线程数,还有……还有那个阻塞队列。 面试官:还行。那线程池的工作流程是怎样的? 王铁牛:就是来了任务,先看核心线程有没有满,满了就放队列里,队列满了就看最大线程数,要是还不行就拒绝策略处理。 面试官:那常见的拒绝策略有哪些? 王铁牛:有那个……直接拒绝,还有……让调用者自己处理。
第三轮面试 面试官:谈谈Spring框架,Spring的IOC是什么? 王铁牛:IOC就是控制反转,把对象的创建和管理交给Spring容器,这样代码耦合度就低了。 面试官:那Spring AOP呢? 王铁牛:AOP是面向切面编程,能把一些通用功能,像日志、事务,切到业务逻辑里。 面试官:在Spring Boot项目中,怎么实现自定义配置属性? 王铁牛:嗯……好像是在配置文件里写,然后在类里用注解获取。
面试总结:从整体面试过程来看,你在一些基础的Java知识方面回答得不错,像基本数据类型、ArrayList和HashMap的区别等。但在一些稍微深入的问题,比如线程池的工作流程细节、常见拒绝策略的完整阐述,以及Spring Boot自定义配置属性的具体实现上,回答得不够清晰和全面。我们后续会综合评估所有面试者的情况,你回去等通知吧,无论结果如何,希望你在技术学习上继续努力,不断提升自己的能力。
问题答案:
- Java基本数据类型:Java有8种基本数据类型。整型:byte(1字节)、short(2字节)、int(4字节)、long(8字节),用于表示整数;浮点型:float(4字节)、double(8字节),用于表示小数;字符型:char(2字节),用于表示单个字符;布尔型:boolean,只有true和false两个值,用于逻辑判断。
- 自动装箱和拆箱:自动装箱是Java编译器在编译期自动将基本数据类型转换为对应的包装类型,例如int i = 10; Integer integer = i; 这里编译器会自动调用Integer.valueOf(i)方法。拆箱则是将包装类型转换为基本数据类型,例如Integer integer = 10; int i = integer; 编译器会自动调用integer.intValue()方法。
- ArrayList和HashMap存储结构区别:ArrayList基于动态数组实现,它按顺序存储元素,有索引,可以通过索引快速访问元素。HashMap基于哈希表,它通过对键进行哈希运算来确定存储位置,以键值对形式存储数据,无序,查找元素时通过键的哈希值能快速定位。
- 线程池核心参数:核心线程数(corePoolSize):线程池中常驻的线程数,即使这些线程处于空闲状态也不会被销毁,除非设置了allowCoreThreadTimeOut为true。最大线程数(maximumPoolSize):线程池允许创建的最大线程数。阻塞队列(workQueue):用于存放任务的队列,当核心线程都在忙碌且队列未满时,新任务会被放入队列。还有keepAliveTime(线程存活时间),当线程数大于核心线程数时,多余的空闲线程在多长时间后会被销毁;TimeUnit(时间单位),keepAliveTime的时间单位。
- 线程池工作流程:当有新任务提交时,首先判断核心线程数是否已满,如果未满则创建新的核心线程来处理任务;若核心线程已满,则将任务放入阻塞队列;若阻塞队列也已满,此时判断线程数是否达到最大线程数,若未达到则创建新的非核心线程来处理任务;若线程数已达到最大线程数,则根据拒绝策略来处理该任务。
- 常见拒绝策略:AbortPolicy(直接拒绝):直接抛出RejectedExecutionException异常。CallerRunsPolicy(调用者运行):将任务交给调用execute方法的线程来执行。DiscardPolicy(丢弃任务):直接丢弃新来的任务,不做任何处理。DiscardOldestPolicy(丢弃最老任务):丢弃队列中最老的任务(队首任务),然后尝试将新任务放入队列。
- Spring IOC:控制反转(Inversion of Control),是一种设计思想。传统方式是在类内部通过new来创建依赖对象,耦合度高。而在Spring中,由Spring容器负责创建对象、管理对象的生命周期和依赖关系。例如一个Service类依赖另一个Dao类,在Spring中通过配置或注解,让Spring容器将Dao对象注入到Service类中,这样Service类不需要自己创建Dao对象,实现了控制权的反转,降低了代码耦合度。
- Spring AOP:面向切面编程(Aspect - Oriented Programming),它将一些通用功能(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,形成一个个切面(Aspect)。这些切面可以在不修改原有业务逻辑代码的情况下,通过切点(Pointcut)定义在哪些地方应用切面逻辑,通过通知(Advice)定义在切点处执行的具体操作,如在方法执行前、后、异常时等执行特定逻辑,从而实现代码的复用和业务逻辑的解耦。
- Spring Boot自定义配置属性:首先在application.properties或application.yml文件中定义属性,例如在application.yml中:myapp: name: test value: 123 。然后创建一个Java类,使用@ConfigurationProperties注解绑定这些属性,例如:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private String name;
private int value;
// 生成getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
在需要使用这些属性的地方,通过依赖注入MyAppProperties类即可获取自定义配置属性的值。