后端开发校招面试常见问答总结(一)|Java高频考点解析
1. HashMap底层原理(出现频率98%)
问题:HashMap如何解决哈希冲突?JDK8做了哪些优化?
回答要点:
-
数组+链表/红黑树结构(JDK8后链表长度>8转红黑树)
-
二次哈希计算索引:(n-1) & hash
-
扩容机制:2倍扩容,rehash时采用高位掩码优化
技巧:随手画存储结构图,提到线程安全问题引出ConcurrentHashMap
2. 线程池七大参数(出现频率95%)
背诵口诀:
"核心最大存活时,队列线程工厂拒绝策"
ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)
3. Java三大特性如何理解?
// 封装:隐藏实现细节
class BankAccount {
private double balance; // 私有属性
public void deposit(double amount) {
if(amount > 0) balance += amount;
}
}
// 继承:复用代码
class Animal {}
class Dog extends Animal {} // Dog继承Animal
// 多态:同一接口不同实现
Animal myPet = new Dog(); // 父类引用指向子类对象
4. String为什么设计成不可变?
-
线程安全:天然线程安全,无需同步
-
缓存哈希值:字符串常用作HashMap键,避免重复计算
-
字符串常量池:节省内存空间(如
String s = "abc"
直接复用) -
典型场景:网络连接参数、文件路径等敏感数据防止篡改
5. ==和equals()的区别
记忆口诀:==
比地址,equals
比内容(需重写)
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(比较内存地址)
System.out.println(s1.equals(s2)); // true(比较内容)
6. final关键字的三大用法
-
修饰类:禁止继承(如String类)
-
修饰方法:禁止子类重写(如模板方法模式)
-
修饰变量:基本类型值不可变,引用类型地址不可变
final List<String> list = new ArrayList<>();
list.add("Java"); // 允许操作
list = new ArrayList<>(); // 编译报错(地址不可变)
7. 重载(Overload) vs 重写(Override)
重载 | 重写 | |
---|---|---|
发生位置 | 同一个类中 | 父子类之间 |
方法签名 | 必须不同(参数列表) | 必须相同 |
返回类型 | 可以不同 | 相同或子类(协变) |
访问权限 | 无限制 | 不能更严格 |
8. 接口和抽象类的区别
使用场景选择:
-
需要多继承 → 接口
-
有公共代码复用 → 抽象类
-
定义行为规范 → 接口
-
需要维护状态 → 抽象类
9. ArrayList和LinkedList区别
// 添加元素效率对比
List<Integer> arrayList = new ArrayList<>(); // 随机访问快(O(1))
List<Integer> linkedList = new LinkedList<>(); // 增删快(O(1)头部操作)
// 内存占用:LinkedList每个节点多存储两个指针
10. HashMap并发问题场景还原
// 多线程扩容导致死循环(JDK7之前)
// 假设初始容量2,线程A和B同时触发扩容
// 在rehash过程中可能形成环形链表
11. ConcurrentHashMap如何保证线程安全?
-
JDK7:分段锁(Segment继承ReentrantLock)
-
JDK8:CAS + synchronized锁单个Node
-
关键设计:
-
volatile修饰Node的val和next
-
扩容时协助迁移机制
-
12. 深拷贝与浅拷贝实现方式
// 浅拷贝示例
class Person implements Cloneable {
String name;
Address address; // 引用类型
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 默认浅拷贝
}
}
// 深拷贝实现(需递归克隆引用对象)
13. 异常处理机制最佳实践
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
// 自动关闭资源(实现AutoCloseable接口)
} catch (IOException | SQLException e) { // 多重捕获
// 不要吞掉异常(至少打印日志)
throw new CustomException("处理失败", e); // 异常链
} finally {
// 避免在finally中return(会覆盖try中的返回值)
}
14. 反射破坏单例的解决方案
// 枚举单例(推荐)
public enum Singleton {
INSTANCE;
public void doSomething() { ... }
}
// 防止反射调用构造器
private Singleton() {
if (INSTANCE != null) {
throw new RuntimeException("禁止反射创建实例");
}
}
15. 动态代理实现方式对比
JDK动态代理 | CGLIB动态代理 | |
---|---|---|
代理对象要求 | 必须实现接口 | 可代理普通类 |
性能 | 生成快,调用慢 | 生成慢,调用快 |
方法拦截 | 通过InvocationHandler | 通过MethodInterceptor |
典型应用 | Spring AOP默认策略 | @Transactional注解代理 |
16. Java值传递的底层原理
void change(int num, String str, List<Integer> list) {
num = 100; // 不影响原值
str = "new"; // 指向新对象
list.add(100); // 修改共享对象
}
// 调用示例
int a = 10;
String s = "old";
List<Integer> lst = new ArrayList<>();
change(a, s, lst);
// a=10, s="old", lst.size()=1
17. 泛型擦除带来的问题
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
// 运行时类型相同
System.out.println(strList.getClass() == intList.getClass()); // true
// 类型擦除导致的问题案例
public static <T> void addToList(List<T> list, Object item) {
list.add((T) item); // 编译警告,运行时可能报错
}
18. 什么是Java内存模型(JMM)?
Java内存模型(JMM)是Java语言规范的一部分,它定义了线程如何与内存交互。JMM的核心目标是确保线程之间的操作能够正确地反映在主内存中。它包括主内存和线程的工作内存的概念,以及变量的读写规则
19. 如何解决多线程环境下的线程安全问题?
-
解决线程安全问题的常见方法包括:
-
使用同步机制(如
synchronized
关键字或ReentrantLock
)。 -
使用线程安全的类(如
ConcurrentHashMap
)。 -
使用不可变对象(如
String
)。 -
使用原子类(如
AtomicInteger
)。
-
20. 什么是事务?事务的ACID特性分别是什么?
-
事务是一组逻辑操作单元,确保数据操作的完整性和一致性。ACID特性包括:
-
原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成。
-
一致性(Consistency):事务执行前后,数据从一个一致的状态转换到另一个一致的状态。
-
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务。
-
持久性(Durability):事务一旦提交,其结果就是永久的。
-
21. Spring框架的核心组件有哪些?
-
Spring框架的核心组件包括:
-
BeanFactory
:用于创建和管理Bean。 -
ApplicationContext
:提供了更高级的Bean管理功能。 -
BeanPostProcessor
:用于在Bean初始化前后进行处理。 -
BeanFactoryPostProcessor
:用于在BeanFactory加载后进行处理。
-
22. Spring中@Component
、@Service
、@Controller
、@Repository
的区别是什么?
-
这些注解都是
@Component
的衍生注解,用于标记不同层次的类:-
@Controller
用于标记控制器层。 -
@Service
用于标记业务逻辑层。 -
@Repository
用于标记数据访问层。
-
23. 如何实现一个线程安全的单例模式?
-
实现线程安全的单例模式可以使用懒汉式(双重校验锁)、饿汉式、枚举单例等方式。其中,双重校验锁是一种常用的懒汉式实现方式。
24. 什么是设计模式?请列举几种常见的设计模式。
-
设计模式是解决一类问题的通用解决方案。常见的设计模式包括:
-
单例模式:确保一个类只有一个实例。
-
工厂模式:用于创建对象,而无需指定具体的类。
-
策略模式:定义一系列算法,将每个算法封装起来,并使它们可以互换。
-
25. 什么是反射?反射的作用是什么?
-
反射是指在运行时动态地获取类的信息(如类的属性、方法等),并调用对象的方法。反射可以用于动态加载类、动态调用方法等。
26. 什么是动态代理?动态代理的作用是什么?
-
动态代理是指在运行时动态地创建代理对象,并在代理对象上调用方法。动态代理可以用于实现AOP(面向切面编程)、事务管理等功能。
27. 什么是JVM?JVM的内存结构包括哪些部分?
-
JVM是Java虚拟机,是Java程序运行的环境。JVM的内存结构包括堆(Heap)、栈(Stack)、方法区(Method Area)、本地方法栈(Native Method Stack)等。
28. 如何优化JVM的性能?
-
可以通过调整堆大小(
-Xms
、-Xmx
)、调整垃圾回收器(如-XX:+UseG1GC
)、调整垃圾回收参数(如-XX:MaxGCPauseMillis
)等方式优化JVM性能。
29. 什么是垃圾回收(GC)?常见的垃圾回收算法有哪些?
-
垃圾回收是指自动回收不再使用的对象占用的内存。常见的垃圾回收算法包括标记-清除算法、复制算法、标记-压缩算法。
30. 什么是数据库索引?索引的作用是什么?
-
索引是数据库中用于快速查找数据的一种数据结构。索引可以提高查询效率,但会增加插入、删除和更新操作的开销。
31. 如何优化SQL查询性能?
-
可以通过添加索引、优化查询语句(如避免全表扫描)、使用合适的连接方式(如内连接、外连接)等方式优化SQL查询性能。
32. 什么是RESTful API?它的特点是什么?
-
RESTful API是一种基于HTTP协议的网络应用程序接口设计风格。它的特点包括无状态、统一接口、资源导向。
33. 什么是微服务架构?微服务架构的优点是什么?
-
微服务架构是一种将复杂应用程序分解为一组小型、独立服务的架构风格。它的优点包括高可扩展性、高可用性、技术栈灵活。
34. 什么是分布式系统?分布式系统的特点是什么?
-
分布式系统是由多个独立计算机组成的系统,这些计算机通过网络协同工作。分布式系统的特点包括高可用性、高扩展性、容错性。
35. 什么是消息队列?消息队列的作用是什么?
-
消息队列是一种用于应用程序之间异步通信的中间件。消息队列可以用于解耦系统、提高系统性能、实现异步处理。
36. 什么是缓存?常见的缓存策略有哪些?
-
缓存是一种用于存储热点数据的技术,可以减少对数据库的访问次数。常见的缓存策略包括LRU(最近最少使用)、FIFO(先进先出)。
37. 什么是事务传播行为?常见的事务传播行为有哪些?
-
事务传播行为是指在一个事务中调用另一个事务时,事务的传播方式。常见的事务传播行为包括
REQUIRED
、REQUIRES_NEW
、SUPPORTS
、NOT_SUPPORTED
、MANDATORY
、NEVER
、NESTED
。
38. 什么是Spring Boot?Spring Boot的优点是什么?
-
Spring Boot是一个基于Spring框架的快速开发框架。它的优点包括简化配置、自动配置、独立运行、无需部署WAR文件。
39. 什么是Spring Security?Spring Security的作用是什么?
-
Spring Security是一个用于保护应用程序的安全框架。它可以用于实现用户认证、授权、防止CSRF攻击等功能。
40. 什么是OAuth 2.0?OAuth 2.0的作用是什么?
-
OAuth 2.0是一种授权框架,用于允许第三方应用程序访问用户在某个服务上的数据。它通过授权码、访问令牌等方式实现安全授权。
41. 什么是JWT(JSON Web Token)?JWT的作用是什么?
-
JWT是一种基于JSON的开放标准,用于在客户端和服务器之间安全地传递信息。JWT可以用于实现无状态的用户认证。
42. 什么是单元测试?常见的单元测试框架有哪些?
-
单元测试是对程序中的最小可测试单元进行测试。常见的单元测试框架包括JUnit、TestNG。
43. 什么是集成测试?集成测试的作用是什么?
-
集成测试是对多个模块组合后的测试,用于验证模块之间的接口是否正确。集成测试可以发现模块之间的集成问题。
44. 什么是压力测试?压力测试的作用是什么?
-
压力测试是通过模拟高负载场景来测试系统的性能和稳定性。压力测试可以发现系统在高负载下的瓶颈。
45. 什么是代码覆盖率?代码覆盖率的作用是什么?
-
代码覆盖率是指被测试代码的比例。代码覆盖率可以用于评估测试的充分性。
46. 什么是日志框架?常见的日志框架有哪些?
-
日志框架用于记录应用程序的运行日志。常见的日志框架包括Log4j、SLF4J、Logback。
47. 什么是依赖注入(DI)?依赖注入的作用是什么?
-
依赖注入是一种设计模式,用于将对象的依赖关系注入到对象中。依赖注入可以降低耦合度,提高代码的可维护性。
48. 什么是AOP(面向切面编程)?AOP的作用是什么?
-
AOP是一种编程范式,用于将横切关注点(如日志、事务管理等)从业务逻辑中分离出来。AOP可以提高代码的可维护性和可扩展性。
49. 什么是事务隔离级别?常见的事务隔离级别有哪些?
-
事务隔离级别用于控制并发事务之间的隔离程度。常见的事务隔离级别包括
READ UNCOMMITTED
、READ COMMITTED
、REPEATABLE READ
、SERIALIZABLE
。
50. 什么是乐观锁和悲观锁?它们的区别是什么?
-
乐观锁:假设冲突较少,通过版本号或时间戳来检测冲突。
-
悲观锁:假设冲突较多,通过锁机制来防止冲突。
-
区别:乐观锁适用于冲突较少的场景,悲观锁适用于冲突较多的场景。
51. 什么是数据库连接池?数据库连接池的作用是什么?
-
数据库连接池是一种用于管理数据库连接的技术。它可以提高数据库连接的复用性,减少连接创建和销毁的开销。
52. 什么是分库分表?分库分表的作用是什么?
-
分库分表是将数据分散到多个数据库或表中,以提高系统的扩展性和性能。分库分表可以解决单表数据量过大导致的性能瓶颈。
53. 什么是乐观锁和悲观锁?它们的优缺点是什么?
-
乐观锁:
-
缺点:在高并发场景下,可能会导致频繁的冲突和重试。
-
优点:减少锁的开销,提高系统性能。
-
-
悲观锁:
-
优点:在高并发场景下,可以有效防止冲突。
-
缺点:锁的开销较大,可能导致性能瓶颈。
-
54. 什么是数据库事务的ACID特性?如何理解它们?
-
原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成。
-
一致性(Consistency):事务执行前后,数据从一个一致的状态转换到另一个一致的状态
-
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务。
-
持久性(Durability):事务一旦提交,其结果就是永久的。
55. 什么是事务的隔离级别?它们的区别是什么?
-
READ UNCOMMITTED:最低的隔离级别,允许读取未提交的数据。
-
READ COMMITTED:允许读取已提交的数据,但可能会出现不可重复读。
-
REPEATABLE READ:保证在同一个事务中多次读取同一数据时,结果是一致的。
- SERIALIZABLE:最高的隔离级别,事务串行执行,不会出现并发问题。
56. 什么是乐观锁和悲观锁?它们的适用场景是什么?
-
乐观锁:适用于冲突较少的场景,例如电商系统中用户浏览商品。
-
悲观锁:适用于冲突较多的场景,例如银行转账。
57. 什么是分库分表?分库分表的优缺点是什么?
-
优点:
-
减少单表数据量,提高查询效率。
-
提高系统的扩展性和性能。
-
- 缺点:
-
增加系统复杂性。
-
需要解决分布式事务问题。
-
58. 什么是数据库连接池?数据库连接池的优缺点是什么?
-
优点:
-
减少连接创建和销毁的开销。
-
提高数据库连接的复用性。
-
- 缺点:
-
如果连接池配置不当,可能会导致连接耗尽。
-
59. 什么是乐观锁和悲观锁?如何实现它们?
-
乐观锁:通过版本号或时间戳来实现。
-
悲观锁:通过数据库锁机制(如
SELECT ... FOR UPDATE
)来实现。
60. 什么是数据库事务的ACID特性?如何实现它们?
-
原子性:通过事务日志来实现。
-
一致性:通过事务的约束和规则来实现。
-
隔离性:通过事务隔离级别来实现。
-
持久性:通过事务日志和数据库的持久化机制来实现。
61. 进程 vs 线程
维度 | 进程 | 线程 |
---|---|---|
资源开销 | 独立内存空间,开销大 | 共享进程资源,开销小 |
通信方式 | 管道、消息队列、Socket | 共享内存、wait/notify |
崩溃影响 | 不影响其他进程 | 导致所属进程终止 |
适用场景 | 需要严格隔离的任务 | 高并发IO操作 |
62. HTTP 1.1 vs HTTP/2 核心改进
1. 多路复用:一个连接并行多个请求(解决队头阻塞)
2. 头部压缩:HPACK算法减少重复头部
3. 服务器推送:主动推送关联资源
4. 二进制分帧:提升解析效率
63. TCP vs UDP 协议对比
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接 | 无连接 |
可靠性 | 保证数据完整有序 | 尽力而为 |
传输效率 | 慢(三次握手等) | 快 |
适用场景 | 文件传输、网页浏览 | 视频会议、实时游戏 |
类比理解:TCP像寄挂号信,UDP像普通明信片
64. 索引失效的六大典型场景
-
对索引列进行运算:
WHERE price+10 > 100
-
使用前导模糊查询:
LIKE '%关键字%'
-
隐式类型转换:
varchar列用WHERE id=123
-
联合索引跳过最左列:
INDEX(a,b,c)
但查询WHERE b=1
-
使用OR连接非索引列:
WHERE a=1 OR b=2
-
数据分布倾斜:查询条件覆盖超过30%数据
65. 负载均衡算法对比
算法 | 特点 | 适用场景 |
---|---|---|
轮询 | 均匀分配请求 | 服务器性能均衡 |
加权轮询 | 按权重分配 | 异构服务器集群 |
最小连接数 | 动态感知服务器压力 | 长连接服务(如WebSocket) |
IP Hash | 同一客户端固定访问某服务器 | 需要会话保持 |
66. 常见状态码语义速查
状态码 | 含义 | 常见场景 |
---|---|---|
200 OK | 请求成功 | 正常返回 |
301 | 永久重定向 | 网站改版换域名 |
400 | 客户端请求错误 | 参数校验失败 |
401 | 未认证 | 未登录访问需要权限的接口 |
403 | 禁止访问 | 权限不足 |
404 | 资源不存在 | 请求路径错误 |
500 | 服务器内部错误 | 代码异常 |
502 | 网关错误 | Nginx连接后端服务失败 |
如果还有其他问题,欢迎随时在评论区留言交流,我也会努力学习,还请大家多多指教!