Java 常见面试题及答案汇总
系统梳理了 Java 开发领域的核心面试题,内容覆盖基础语法、集合框架、多线程并发、JVM 内存模型与垃圾回收、Spring 容器与 AOP 事务机制、数据库 JDBC 与 MyBatis 持久层技术,以及设计模式与性能优化策略。通过理论结合代码示例,深入解析 HashMap 底层实现、线程池参数配置、类加载双亲委派模型等高频考点,旨在帮助读者巩固知识体系,提升面试通过率与实战能力。

系统梳理了 Java 开发领域的核心面试题,内容覆盖基础语法、集合框架、多线程并发、JVM 内存模型与垃圾回收、Spring 容器与 AOP 事务机制、数据库 JDBC 与 MyBatis 持久层技术,以及设计模式与性能优化策略。通过理论结合代码示例,深入解析 HashMap 底层实现、线程池参数配置、类加载双亲委派模型等高频考点,旨在帮助读者巩固知识体系,提升面试通过率与实战能力。

答案:
答案:
| 维度 | 基本数据类型(如 int、float) | 包装类(如 Integer、Float) |
|---|---|---|
| 本质 | 原始值,无对象属性 | 引用类型,继承 Object 类 |
| 默认值 | 有(如 int 默认 0,boolean 默认 false) | 无,默认 null |
| 适用场景 | 简单运算、局部变量,效率高 | 集合框架(如 List)、泛型、需要 null 值的场景 |
| 缓存机制 | 无 | 部分包装类(Integer[-128~127]、Byte、Short 等)有常量池缓存 |
关键考点:
int i = new Integer(10)→拆箱,Integer j = 10→装箱);Integer a = 127; Integer b = 127; → a == b为 true(复用缓存);Integer c = 128; Integer d = 128; → c == d为 false(新建对象),需用 equals() 比较值。答案: 核心差异在于可变性和线程安全:
底层原理:
String 的不可变性源于 private final char value[](JDK8),final 修饰数组引用不可变,且数组无暴露修改接口;StringBuffer 和 StringBuilder 继承 AbstractStringBuilder,底层是可变 char 数组,扩容机制为:默认初始容量 16,当长度超过容量时,新容量=原容量×2+2,不足则直接扩容到所需长度。
答案:
易错点:
final int[] arr = {1,2,3}; arr[0] = 4; 合法(数组内容可变);arr = new int[5]; 非法(引用地址不可变)。
答案:
| 维度 | 接口(Interface) | 抽象类(Abstract Class) |
|---|---|---|
| 继承方式 | 多实现(一个类可实现多个接口) | 单继承(一个类只能继承一个抽象类) |
| 成员变量 | 只能是 public static final 常量 | 可包含普通变量、静态变量、常量 |
| 成员方法 | JDK8 前:只能是抽象方法;JDK8+:支持 default/static 方法;JDK9+:支持 private 方法 | 可包含抽象方法、普通方法、静态方法 |
| 构造方法 | 无 | 有(不能实例化,供子类调用) |
| 设计目的 | 定义行为规范,解耦(如 List 接口) | 定义类的模板,复用代码(如 HttpServlet) |
应用场景:
Runnable 接口);AbstractList 封装 List 的公共方法)。答案:
Throwable,包含两个核心子类:
Error:严重错误(如 OutOfMemoryError、StackOverflowError),程序无法恢复,无需捕获;Exception:可处理的异常,分为:
RuntimeException,无需强制捕获。异常处理关键字:
try:包裹可能抛出异常的代码;catch:捕获并处理异常(可多个 catch,按异常子类→父类顺序);finally:无论是否抛出异常,都会执行(常用于关闭资源,如流、数据库连接);throw:手动抛出异常(如 throw new IllegalArgumentException("参数非法"));throws:声明方法可能抛出的异常,告知调用者。最佳实践:
Throwable(包含 Error,无法处理);AutoCloseable 接口的类)。答案:
Java 集合框架核心分为两大体系(均位于 java.util 包):
Collection):存储单个元素,核心子接口:
List:有序、可重复(如 ArrayList、LinkedList、Vector);Set:无序、不可重复(如 HashSet、TreeSet、LinkedHashSet);Map):存储键值对(key-value),核心实现类:HashMap、TreeMap、LinkedHashMap、ConcurrentHashMap。关键特性:
List:支持索引访问,可通过 get(int index) 获取元素;Set:基于 equals() 和 hashCode() 保证元素唯一性;Map:key 不可重复(重复会覆盖 value),value 可重复;JDK8+ 中 Map 提供 forEach()、computeIfAbsent() 等便捷方法。答案:
| 维度 | ArrayList(数组实现) | LinkedList(双向链表实现) |
|---|---|---|
| 底层结构 | 动态数组(Object[]) | 双向链表(每个节点存储 prev、next、value) |
| 访问效率 | 随机访问快(O(1)),通过索引直接定位 | 随机访问慢(O(n)),需遍历链表 |
| 增删效率 | 尾部增删快(O(1)),中间增删慢(需移动数组元素,O(n)) | 中间增删快(O(1),只需修改节点指针),尾部增删需遍历到末尾(O(n),可通过 last 指针优化) |
| 内存占用 | 连续内存,占用少(无额外指针开销) | 非连续内存,每个节点有额外指针开销 |
| 线程安全 | 不安全 | 不安全 |
应用场景:
答案: HashMap 是基于'哈希表'的 Map 实现,核心是'数组 + 链表/红黑树'的结构,目的是平衡查询和增删效率。
hashCode() ^ (hashCode() >>> 16))得到哈希值;哈希冲突解决:
线程安全问题: HashMap 线程不安全,多线程环境下可能出现:
ConcurrentHashMap 或 Collections.synchronizedMap(new HashMap<>())。答案: ConcurrentHashMap 是 HashMap 的线程安全版本,核心差异在于锁机制:
computeIfAbsent()、forEach() 等原子操作,性能优于 JDK1.7。答案: HashSet 底层依赖 HashMap 实现,核心逻辑:
add(E e) → 调用 HashMap 的 put(e, PRESENT),其中 PRESENT 是一个静态空 Object(仅占位,不存储实际值);equals() 和 hashCode() 判断);关键考点:
自定义对象作为 HashSet 元素时,必须重写 equals() 和 hashCode(),否则无法保证唯一性(默认使用 Object 类的方法,比较对象地址)。重写原则:
equals() 返回 true → hashCode() 必须相等;hashCode() 相等 → equals() 不一定返回 true(哈希冲突)。答案:
方式 1:继承 Thread 类,重写 run() 方法(线程执行逻辑),调用 start() 方法启动线程(底层调用 start0() native 方法创建操作系统线程):
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running");
}
}
// 启动
new MyThread().start();
方式 2:实现 Runnable 接口,重写 run() 方法,将实例传入 Thread 类启动:
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable running");
}
}
// 启动
new Thread(new MyRunnable()).start();
方式 3:实现 Callable 接口,重写 call() 方法(支持返回值和抛出异常),通过 FutureTask 包装后传入 Thread 启动:
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "Callable result";
}
}
// 启动
FutureTask<String> future = new FutureTask<>(new MyCallable());
new Thread(future).start();
String result = future.get(); // 获取返回值(阻塞直到线程完成)
对比:
答案:
Java 线程有 6 种状态(定义在 Thread.State 枚举中),状态转换如下:
NEW:线程创建后未启动(未调用 start());RUNNABLE:线程启动后,处于可运行状态(包含操作系统的'运行中'和'就绪');BLOCKED:线程等待同步锁(如 synchronized 未获取锁时);WAITING:线程无限期等待(如调用 Object.wait()、Thread.join()、LockSupport.park(),需其他线程唤醒);TIMED_WAITING:线程限时等待(如调用 Thread.sleep(ms)、Object.wait(ms)、Thread.join(ms),超时自动唤醒);TERMINATED:线程执行完成或异常终止。核心转换路径:
NEW → RUNNABLE(start()) → TERMINATED(执行完成);
RUNNABLE → BLOCKED(竞争锁失败) → RUNNABLE(获取锁);
RUNNABLE → WAITING/TIMED_WAITING(调用等待方法) → RUNNABLE(被唤醒/超时)。
答案:
| 维度 | synchronized(内置锁) | Lock(显式锁,如 ReentrantLock) |
|---|---|---|
| 锁实现 | JVM 层面实现(C++ 代码) | JDK 层面实现(Java 代码) |
| 锁获取与释放 | 自动获取(进入同步块)、自动释放(退出同步块/异常) | 手动获取(lock())、手动释放(unlock(),需在 finally 中执行) |
| 锁类型 | 可重入锁、非公平锁(默认),JDK6+ 支持偏向锁/轻量级锁/重量级锁升级 | 可重入锁,支持公平锁/非公平锁(构造函数指定) |
| 功能扩展 | 无(仅支持基础同步) | 支持中断锁(lockInterruptibly())、超时锁(tryLock(ms))、条件变量(Condition)、读写锁(ReentrantReadWriteLock) |
| 性能 | JDK6+ 优化后,性能接近 Lock | 高并发场景下性能更优,灵活度高 |
应用场景:
答案: volatile 是 Java 提供的轻量级同步机制,核心作用有两个:
局限性:
volatile int i = 0; i++; 非原子操作(包含读取、加 1、写入三步),多线程下可能出现计数错误,需配合 synchronized 或 AtomicInteger 使用;volatile boolean flag = false; 控制线程启停)。经典应用:双重校验锁(DCL)单例模式:
public class Singleton {
// volatile 禁止指令重排,防止 instance 未初始化完成就被其他线程获取
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
// 第一次校验(无锁,提高效率)
synchronized (Singleton.class) {
// 加锁
if (instance == null) {
// 第二次校验(防止多线程并发创建)
instance = new Singleton(); // 禁止重排:分配内存→初始化→赋值
}
}
}
return instance;
}
}
答案:
Java 线程池核心类是 ThreadPoolExecutor,基于'池化思想'减少线程创建/销毁开销,提高并发效率。
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数(常驻线程,即使空闲也不销毁)
int maximumPoolSize, // 最大线程数(核心线程 + 临时线程的总上限)
long keepAliveTime, // 临时线程空闲时间(超过则销毁)
TimeUnit unit, // keepAliveTime 的时间单位
BlockingQueue<Runnable> workQueue, // 任务阻塞队列(核心线程满时,任务入队)
ThreadFactory threadFactory, // 线程创建工厂(自定义线程名称、优先级等)
RejectedExecutionHandler handler // 拒绝策略(队列和最大线程数都满时,处理新任务)
)
AbortPolicy(默认):直接抛出 RejectedExecutionException;CallerRunsPolicy:由提交任务的线程(调用者)执行任务;DiscardPolicy:直接丢弃新任务,无异常;DiscardOldestPolicy:丢弃队列中最旧的任务,加入新任务。Executors.newFixedThreadPool(n):固定核心线程数和最大线程数(n),队列无界(LinkedBlockingQueue);Executors.newCachedThreadPool():核心线程数 0,最大线程数 Integer.MAX_VALUE,临时线程空闲 60 秒销毁,队列同步移交(SynchronousQueue);Executors.newSingleThreadExecutor():核心线程数 1,最大线程数 1,队列无界,保证任务串行执行;Executors.newScheduledThreadPool(n):核心线程数 n,支持定时/延迟执行任务(ScheduledFutureTask)。注意:阿里巴巴 Java 开发手册禁止使用 Executors 创建线程池,原因是:
newFixedThreadPool/newSingleThreadExecutor:队列无界,可能导致 OOM;newCachedThreadPool:最大线程数无界,可能创建大量线程导致 CPU/内存耗尽。
推荐直接使用 ThreadPoolExecutor 构造方法,指定合理参数(如核心线程数=CPU 核心数±1,队列使用有界队列)。答案: ThreadLocal 是线程本地存储工具,允许每个线程拥有独立的变量副本,避免多线程共享变量的并发问题。
ThreadLocalMap(ThreadLocal 的内部类),ThreadLocalMap 的 key 是 ThreadLocal 实例(弱引用),value 是线程本地变量副本;set(T value):获取当前线程的 ThreadLocalMap,将(当前 ThreadLocal 实例,value)存入;get():获取当前线程的 ThreadLocalMap,根据当前 ThreadLocal 实例获取 value,无则调用 initialValue() 初始化;remove():删除当前线程的 ThreadLocalMap 中对应的键值对。WeakReference<ThreadLocal<?>>),当 ThreadLocal 实例被回收(如外部引用置 null),key 会变成 null,而 value 是强引用,若线程未结束(如线程池核心线程),value 无法被 GC 回收,导致内存泄漏;remove() 方法删除 value;应用场景:
RequestContextHolder 底层使用 ThreadLocal 存储 HttpServletRequest)。答案: JVM 运行时数据区分为 5 个部分(基于 JDK8):
StackOverflowError(如递归调用无终止);栈扩展时内存不足→OutOfMemoryError。StackOverflowError 和 OutOfMemoryError。-Xms(初始堆大小)、-Xmx(最大堆大小)配置;-XX:MetaspaceSize、-XX:MaxMetaspaceSize 配置)。OutOfMemoryError: Java heap space;元空间不足→OutOfMemoryError: Metaspace。答案: GC 是 JVM 自动回收堆中无用对象(无引用的对象)的过程,核心目标是释放内存,避免内存泄漏。
答案: 类加载是将.class 字节码文件加载到 JVM 内存,生成 Class 对象的过程,核心分为 5 个阶段:
<clinit>() 方法(静态变量赋值 + 静态代码块执行),初始化顺序:父类→子类,静态变量→静态代码块。rt.jar),无父加载器;jre/lib/ext 目录下的类库;ClassLoader 类,重写 findClass() 方法,用于加载自定义路径的类(如热部署、加密类)。java.lang.String 仅由启动类加载器加载一次);java.lang.String 类替换核心类)。答案: IoC(Inversion of Control,控制反转)是 Spring 的核心思想,指将对象的创建、依赖注入(DI)的控制权从应用程序转移到 Spring 容器,实现解耦。
ApplicationContext、BeanFactory),负责管理 Bean 的生命周期(创建、初始化、销毁)和依赖关系;new 对象)。字段注入:直接在字段上添加 @Autowired 注解,代码简洁,但不推荐(无法通过构造方法校验依赖,不利于单元测试):
@Service
public class UserService {
@Autowired
private UserDao userDao;
}
Setter 方法注入:通过 Setter 方法注入依赖,适用于可选依赖:
@Service
public class UserService {
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
构造方法注入:通过 Bean 的构造方法传入依赖,推荐使用(强制依赖,避免空指针):
@Service
public class UserService {
private final UserDao userDao;
// 构造方法注入(@Autowired 可省略,Spring 4.3+ 支持)
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
@Configuration);@Component、@Service、@Repository),注册到 BeanDefinitionRegistry;@PostConstruct 注解方法、InitializingBean 接口的 afterPropertiesSet() 方法、自定义 init-method;@PreDestroy 注解方法、DisposableBean 接口的 destroy() 方法、自定义 destroy-method。答案: AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 的核心特性,通过'横切'机制,将日志、事务、权限等通用功能(切面)与业务逻辑解耦,实现代码复用。
@Before:目标方法执行前执行;@After:目标方法执行后执行(无论是否异常);@AfterReturning:目标方法正常返回后执行;@AfterThrowing:目标方法抛出异常后执行;@Around:环绕目标方法执行(可控制目标方法的执行与否,如事务的开始和提交);Spring AOP 基于动态代理实现,分为两种代理方式:
java.lang.reflect.Proxy 类动态生成代理类,代理类实现目标接口,并重写目标方法,在方法中织入切面逻辑;// 切面类
@Aspect
@Component
public class LogAspect {
// 切入点:所有 com.example.service 包下的 public 方法
@Pointcut("execution(public * com.example.service..*(..))")
public void servicePointcut() {}
// 环绕通知
@Around("servicePointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 目标方法执行前:打印请求参数
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("方法" + methodName + "调用,参数:" + Arrays.toString(args));
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行目标方法
// 目标方法执行后:打印返回值和执行时间
long cost = System.currentTimeMillis() - start;
System.out.println("方法" + methodName + "返回值:" + result + ",执行时间:" + cost + "ms");
return result;
}
}
答案: Spring 事务管理核心是'声明式事务'(基于 AOP)和'编程式事务'(手动编码),其中声明式事务是主流用法。
DEFAULT:默认隔离级别(依赖数据库,如 MySQL 默认 REPEATABLE READ);READ_UNCOMMITTED:读未提交,最低隔离级别,可能出现脏读、不可重复读、幻读;READ_COMMITTED:读已提交,避免脏读,可能出现不可重复读、幻读(如 Oracle 默认);REPEATABLE_READ:可重复读,避免脏读、不可重复读,可能出现幻读(如 MySQL 默认);SERIALIZABLE:串行化,最高隔离级别,避免所有并发问题,性能最低。Spring 定义了 7 种传播行为,常用的有:
REQUIRED(默认):如果当前存在事务,加入事务;如果没有事务,创建新事务;REQUIRES_NEW:无论当前是否存在事务,都创建新事务(新事务与原事务相互独立,原事务暂停);SUPPORTS:如果当前存在事务,加入事务;如果没有事务,以非事务方式执行;NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,暂停原事务;NEVER:以非事务方式执行,如果当前存在事务,抛出异常。@EnableTransactionManagement 注解启用事务管理(Spring Boot 自动启用);@Transactional(标注在类或方法上,类级别的注解对所有方法生效);@Transactional 注解被解析为切面,切入点是标注该注解的方法;PlatformTransactionManager 接口适配不同数据库(如 DataSourceTransactionManager 适配 JDBC,HibernateTransactionManager 适配 Hibernate)。@Transactional 仅对 public 方法生效);@Transactional 失效,因为未经过代理类);RuntimeException 和 Error,checked 异常需通过 rollbackFor 指定);try-catch 异常但未 throw,事务无法感知异常,不会回滚);NOT_SUPPORTED、NEVER);PlatformTransactionManager 未被 Spring 管理)。答案: JDBC(Java Database Connectivity)是 Java 访问数据库的标准 API,核心步骤如下:
DriverManager.getConnection(url, username, password));executeQuery() 查询,executeUpdate() 增删改);示例代码:
public void queryUser() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 1. 加载驱动(MySQL 8.0+ 驱动类:com.mysql.cj.jdbc.Driver)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
String url = "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC";
conn = DriverManager.getConnection(url, "root", "123456");
// 3. 创建 PreparedStatement(预编译 SQL,防止 SQL 注入)
String sql = "SELECT id, name FROM user WHERE id = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 1); // 设置参数
// 4. 执行查询
rs = pstmt.executeQuery();
// 5. 处理结果集
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println("id: " + id + ", name: " + name);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 6. 关闭资源(逆序关闭)
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
关键考点:
SELECT * FROM user WHERE + name + "'",若 name 传入 ' OR '1'='1,则 SQL 变为 SELECT * FROM user WHERE OR '1'='1',查询所有用户;PreparedStatement 通过参数绑定避免该问题。答案: MyBatis 是持久层框架,简化 JDBC 操作,通过 XML 或注解配置 SQL 语句,无需手动编写 JDBC 代码。
SqlSessionFactory:MyBatis 核心工厂类,通过 SqlSessionFactoryBuilder 读取配置文件(mybatis-config.xml)创建,线程安全;SqlSession:会话对象,封装数据库连接和事务管理,线程不安全(每次请求创建新实例);Mapper 接口:自定义 DAO 接口,MyBatis 通过动态代理生成实现类,关联 XML/注解中的 SQL;Mapper.xml:配置 SQL 语句、参数映射、结果集映射;Configuration:MyBatis 全局配置对象,存储核心配置(如数据源、事务管理器、Mapper 注册)。SqlSessionFactoryBuilder 读取 mybatis-config.xml 和 Mapper.xml,解析配置信息(数据源、SQL 语句、映射规则);openSession() 创建 SqlSession,默认不自动提交事务;getMapper(Mapper 接口.class),通过动态代理生成 Mapper 接口的实现类;commit() 提交事务或 rollback() 回滚事务;<configuration>
<!-- 环境配置(数据源、事务管理器) -->
<environments default="development">
<environment>
<transactionManager type="JDBC"/> <!-- 事务管理类型:JDBC/MANAGED -->
<dataSource type="POOLED"> <!-- 数据源类型:POOLED(连接池)/UNPOOLED/JNDI -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 注册 Mapper.xml -->
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
</mappers>
</configuration>
<mapper namespace="com.example.mapper.UserMapper">
<!-- 结果集映射(数据库字段→Java 对象属性) -->
<resultMap type="com.example.entity.User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
</resultMap>
<!-- 查询用户 -->
<select parameterType="int" resultMap="UserResultMap">
SELECT id, name, age FROM user WHERE id = #{id}
</select>
<!-- 新增用户 -->
<insert parameterType="com.example.entity.User">
INSERT INTO user (name, age) VALUES (#{name}, #{age})
</insert>
</mapper>
答案: MyBatis 提供缓存机制,减少数据库查询次数,提升性能,分为一级缓存和二级缓存。
SqlSession.clearCache() 手动清空;<setting name="cacheEnabled" value="true"/>;<cache/> 标签(启用当前 Mapper 的二级缓存);Serializable 接口(二级缓存可能序列化存储);useCache="false"(查询语句)或 flushCache="true"(增删改语句)控制缓存行为。缓存查询顺序:二级缓存 → 一级缓存 → 数据库。
答案: 单例模式确保一个类仅有一个实例,并提供全局访问点,常用实现方式如下:
public class Singleton {
// 类加载时初始化实例(饿汉式)
private static final Singleton instance = new Singleton();
// 私有构造方法,禁止外部实例化
private Singleton() {}
// 提供全局访问方法
public static Singleton getInstance() {
return instance;
}
}
instance = new Singleton() 指令重排(分配内存→初始化→赋值),导致其他线程获取到未初始化的实例。优化版(双重校验锁 DCL,线程安全,懒加载):
public class Singleton {
// volatile 禁止指令重排
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
// 第一次校验(无锁,提高效率)
synchronized (Singleton.class) {
// 加锁
if (instance == null) {
// 第二次校验(防止多线程并发创建)
instance = new Singleton();
}
}
}
return instance;
}
}
基础版(线程不安全,多线程下可能创建多个实例):
public class Singleton {
private static Singleton instance;
private Singleton() {}
// 线程不安全:多线程同时进入 if 条件,创建多个实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
public class Singleton {
private Singleton() {}
// 静态内部类,类加载时不初始化
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
// 调用 getInstance() 时,才加载 SingletonHolder,初始化实例
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
public enum Singleton {
INSTANCE;
// 枚举类的方法
public void doSomething() {
System.out.println("Singleton enum");
}
}
优点:
答案: Java 性能优化需从'代码层面、JVM 层面、数据库层面、架构层面'多维度入手,核心目标是提升响应速度、降低资源消耗。
ArrayList.add(index, element)(O(n) 复杂度);String.intern() 复用常量池对象;for (int i = 0; i < list.size(); i++) → 先获取 size:int size = list.size(); for (int i = 0; i < size; i++));Objects.requireNonNull()、Optional 类,减少 null 判断;-Xms(初始堆)和 -Xmx(最大堆),建议两者相等(避免频繁扩容),堆大小一般为物理内存的 1/2~1/3;-XX:NewRatio(年轻代与老年代比例,默认 2:1)、-XX:SurvivorRatio(Eden 与 S0/S1 比例,默认 8:1),根据应用对象存活时间调整;-XX:+DoEscapeAnalysis(默认启用),JVM 自动分析对象是否逃逸,未逃逸的对象可分配在栈上(减少 GC 压力)。WHERE DATE(create_time) = '2025-01-01',导致索引失效);batchInsert);maximum-pool-size,建议为 CPU 核心数×2+1),避免连接泄漏。本文覆盖 Java 面试核心考点,从基础语法、集合框架、多线程、JVM、Spring、数据库到设计模式与性能优化,每个模块均包含高频面试题、详细答案及核心考点解析,兼顾理论深度与实战应用。
面试时,除了记忆答案,更要理解底层原理(如 HashMap 的哈希冲突解决、Spring AOP 的动态代理、JVM 的 GC 机制),并结合项目经验说明实际应用场景(如线程池在项目中的配置、事务失效的排查过程)。建议重点掌握多线程并发、JVM、Spring 核心原理等高级考点,这些是区分初级与中高级开发者的关键。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online