1. Java八股文:从零基础到精通的完整指南
作为一名Java开发者,面试时经常会被问到各种"八股文"问题。这些问题看似基础,却能全面考察一个程序员对Java核心概念的理解深度。本文将从面试技巧、手写代码、Java SE核心概念、JVM原理、设计模式、数据库、框架等多个维度,为你梳理Java面试中最常被问到的知识点。
1.1 面试准备与技巧
面试不仅是技术能力的较量,更是表达和应变能力的展示。在技术面试前,我们需要做好充分准备:
- 自我介绍:控制在4-5分钟内,简明扼要地介绍自己的技术栈、项目经验和优势
- 常见问题应对:
- 优点:突出技术专长和解决问题的能力
- 缺点:选择不影响工作的"缺点",如"有时过于追求代码完美"
- 离职原因:避免负面评价前公司,强调职业发展需求
- 薪资谈判:非终面不深谈,给出合理区间而非具体数字
提示:面试中最关键的不是你说了什么,而是你怎么说。保持自信、清晰的表达比单纯的技术知识更重要。
2. 手写代码:算法与设计模式
2.1 常见排序算法实现
冒泡排序是最基础的排序算法,时间复杂度O(n²):
java复制public static void bubbleSort(int[] arr) {
for(int i=0; i<arr.length-1; i++) {
for(int j=0; j<arr.length-1-i; j++) {
if(arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
快速排序采用分治思想,平均时间复杂度O(nlogn):
java复制public static void quickSort(int[] arr, int low, int high) {
if(low >= high) return;
int pivot = partition(arr, low, high);
quickSort(arr, low, pivot-1);
quickSort(arr, pivot+1, high);
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low;
for(int j=low; j<high; j++) {
if(arr[j] < pivot) {
swap(arr, i, j);
i++;
}
}
swap(arr, i, high);
return i;
}
2.2 单例模式实现
单例模式确保一个类只有一个实例,并提供一个全局访问点。实现方式有多种:
饿汉式(线程安全,类加载时初始化):
java复制public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
双重检查锁(懒加载,线程安全):
java复制public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类(推荐方式):
java复制public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
3. Java SE核心概念
3.1 面向对象特性
Java面向对象的四大特性:
- 封装:隐藏实现细节,提供公共访问方式
- 继承:子类继承父类特征和行为
- 多态:同一操作作用于不同对象产生不同行为
- 抽象:提取共性形成抽象类或接口
3.2 集合框架
ArrayList vs LinkedList:
- ArrayList基于动态数组,随机访问快(O1),插入删除慢(On)
- LinkedList基于双向链表,插入删除快(O1),随机访问慢(On)
HashMap原理:
- JDK1.8前:数组+链表
- JDK1.8后:数组+链表/红黑树(链表长度>8时转换)
- 扩容机制:默认容量16,负载因子0.75,扩容时容量翻倍
java复制// HashMap put方法核心逻辑
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
// 处理哈希冲突...
}
++modCount;
if (++size > threshold)
resize();
return null;
}
3.3 多线程与并发
线程状态转换:
- NEW:新建状态
- RUNNABLE:可运行状态
- BLOCKED:阻塞状态
- WAITING:等待状态
- TIMED_WAITING:超时等待
- TERMINATED:终止状态
线程池参数:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:空闲线程存活时间
- workQueue:任务队列
- threadFactory:线程工厂
- handler:拒绝策略
java复制ExecutorService threadPool = new ThreadPoolExecutor(
2, 5, 1L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
4. JVM原理与调优
4.1 内存区域
JVM内存主要分为:
- 程序计数器:线程私有,记录当前线程执行位置
- 虚拟机栈:线程私有,存储栈帧(局部变量表、操作数栈等)
- 本地方法栈:为Native方法服务
- 堆:线程共享,存放对象实例
- 方法区:存储类信息、常量、静态变量等
4.2 垃圾回收
GC算法:
- 标记-清除:简单但产生内存碎片
- 复制算法:高效但浪费空间
- 标记-整理:解决碎片问题但效率较低
- 分代收集:结合多种算法,针对不同区域使用不同策略
垃圾收集器:
- Serial:单线程,适合客户端应用
- Parallel Scavenge:吞吐量优先
- CMS:低延迟,已废弃
- G1:区域化分代式,JDK9默认
- ZGC:超低延迟,JDK15生产可用
5. 数据库与框架
5.1 MySQL索引优化
索引类型:
- 主键索引
- 唯一索引
- 普通索引
- 组合索引
- 全文索引
索引失效场景:
- 使用!=或<>操作符
- 对索引列进行运算或函数操作
- 使用OR连接条件
- 不符合最左前缀原则
- 使用LIKE以通配符开头
5.2 Spring框架核心
IoC容器:控制反转,将对象创建和依赖注入交给容器管理
AOP原理:基于动态代理实现横切关注点的模块化
java复制@Aspect
@Component
public class LogAspect {
@Before("execution(* com.example.service.*.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("方法执行前..." + joinPoint.getSignature().getName());
}
}
Spring事务传播行为:
- REQUIRED:默认,当前有事务则加入,没有则新建
- REQUIRES_NEW:新建事务,挂起当前事务
- NESTED:嵌套事务
- SUPPORTS:有事务则加入,没有则以非事务执行
6. 分布式与微服务
6.1 Redis应用场景
- 缓存:减轻数据库压力
- 分布式锁:setnx命令实现
- 计数器:incr/decr命令
- 消息队列:list结构实现
- 会话缓存:共享session
Redis持久化:
- RDB:定时快照,恢复快但可能丢失数据
- AOF:记录写命令,数据安全但文件大
6.2 Spring Cloud组件
- Eureka:服务注册与发现
- Ribbon:客户端负载均衡
- Feign:声明式服务调用
- Hystrix:服务熔断降级
- Zuul/Gateway:API网关
- Config:分布式配置中心
7. 系统设计与性能优化
7.1 高并发系统设计
- 缓存:多级缓存(本地+分布式)
- 限流:令牌桶、漏桶算法
- 降级:非核心服务不可用时提供兜底方案
- 异步:消息队列解耦
- 分库分表:水平/垂直拆分
7.2 JVM调优参数
常用参数:
- -Xms/-Xmx:堆初始/最大大小
- -Xmn:新生代大小
- -XX:SurvivorRatio:Eden/Survivor比例
- -XX:+UseG1GC:使用G1收集器
- -XX:MaxGCPauseMillis:最大GC停顿时间目标
8. 实战经验与避坑指南
在实际开发中,我总结了一些有价值的经验:
-
HashMap初始化:预估容量避免频繁扩容
java复制// 预计存放100个元素,0.75负载因子 Map<String, String> map = new HashMap<>(128); -
线程池使用:避免使用Executors快捷方法,而是明确指定参数
-
数据库连接:记得在finally块中关闭资源
-
日志规范:合理使用不同级别日志,避免过度打印
-
异常处理:捕获具体异常而非Throwable,记录完整堆栈
对于Java开发者来说,持续学习和实践是提升的关键。建议定期:
- 阅读JDK源码
- 参与开源项目
- 学习新技术趋势
- 总结项目经验
记住,面试八股文只是起点,真正的技术实力来自于对原理的深入理解和丰富的实战经验。希望这份指南能帮助你在Java开发道路上走得更远。