Java 后端开发完整学习指南:从零基础到 Spring Boot 企业项目与面试
适合对象:零基础学习 Java、前端转后端、想做 Vue/React + Java 前后端分离项目、准备 Java 后端面试的人。
更新时间:2026-05-28
推荐学习版本:JDK 25 LTS 或企业常用的 JDK 21 LTS。如果只是学习新特性,也可以了解 JDK 26。
目录
- Java 是什么
- Java 应用领域
- JDK、JRE、JVM 区别
- Java 环境安装与开发工具
- Java 程序执行流程
- Java 基础语法
- 方法、数组与字符串
- 面向对象编程 OOP
- 常用 API 与工具类
- 集合框架
- 泛型
- 异常处理
- IO、NIO 与文件操作
- Lambda、Stream API 与 Optional
- 多线程与并发编程
- JVM 核心原理
- 数据库与 MySQL
- JDBC、MyBatis、MyBatis-Plus、JPA
- Java Web 与 HTTP 基础
- Spring、Spring MVC、Spring Boot
- 登录注册、JWT、权限拦截
- Redis、消息队列、搜索、缓存
- Maven、Gradle 与项目构建
- Docker、Linux、Nginx 部署
- Java 企业级项目结构
- Java 学习路线
- Java 官方文档与相关资源表
- Java 面试题与答案
- 项目练习建议
- 总结
一、Java 是什么?
Java 是一门 面向对象、强类型、跨平台、生态成熟 的编程语言。Java 最常见的应用方向是后端开发,尤其是在企业级系统、电商系统、金融系统、支付系统、后台管理系统、微服务系统中非常常见。
Java 的核心特点:
| 特点 | 说明 |
|---|---|
| 跨平台 | Java 程序编译成字节码,由 JVM 在不同系统上运行 |
| 面向对象 | 使用类、对象、封装、继承、多态组织代码 |
| 强类型 | 变量类型明确,编译阶段能发现较多错误 |
| 生态成熟 | Spring、MyBatis、Maven、Redis、MQ、微服务生态完善 |
| 适合大型项目 | 代码规范、稳定性强、企业级框架多 |
| 高并发能力强 | 支持多线程、线程池、并发容器、JVM 调优 |
一句话理解 Java:
Java 是企业后端开发中非常主流的一门语言,尤其适合构建稳定、可维护、可扩展的服务端系统。
二、Java 应用领域
1. 企业后端开发
这是 Java 最大的应用场景。
常见系统包括:
- OA 办公系统
- ERP 企业资源系统
- CRM 客户管理系统
- CMS 内容管理系统
- 电商平台
- 支付系统
- 金融交易系统
- 物流系统
- 后台管理系统
技术组合通常是:
text
Spring Boot + MyBatis/MyBatis-Plus + MySQL + Redis + Spring Security + JWT
2. 前后端分离项目
前端使用 Vue、React、Angular 等框架,后端使用 Java 提供接口。
典型流程:
text
Vue / React 页面
↓ axios/fetch
Spring Boot REST API
↓
Service 业务层
↓
Mapper / Repository
↓
MySQL / Redis
3. 微服务与分布式系统
Java 在微服务领域非常成熟。
常见技术:
- Spring Cloud
- Spring Cloud Alibaba
- Nacos
- Gateway
- OpenFeign
- Sentinel
- Seata
- Redis
- RabbitMQ
- Kafka
- Docker
- Kubernetes
4. 安卓开发
安卓早期主要使用 Java,现在 Kotlin 更主流,但 Java 仍然是安卓生态的重要基础。
5. 大数据生态
很多大数据组件与 Java/JVM 生态相关:
- Hadoop
- HBase
- Flink
- Spark
- Kafka
- Elasticsearch
6. 桌面应用与工具开发
虽然现在不是主流方向,但 Java 仍可以开发桌面程序,例如:
- JavaFX
- Swing
- IntelliJ IDEA 插件
- 企业内部工具
三、JDK、JRE、JVM 区别
| 名称 | 全称 | 作用 |
|---|---|---|
| JDK | Java Development Kit | Java 开发工具包,包含编译器、运行环境、工具 |
| JRE | Java Runtime Environment | Java 运行环境,只负责运行 Java 程序 |
| JVM | Java Virtual Machine | Java 虚拟机,负责执行字节码 |
关系:
text
JDK 包含 JRE
JRE 包含 JVM
JVM 负责运行 .class 字节码
学习和开发时,直接安装 JDK 即可。
四、Java 环境安装与开发工具
1. 推荐 JDK 版本
当前建议:
| 场景 | 推荐版本 |
|---|---|
| 新手学习 | JDK 21 LTS 或 JDK 25 LTS |
| 企业项目 | JDK 17、21、25,视公司技术栈而定 |
| 学习新特性 | JDK 25、JDK 26 |
| 老项目维护 | JDK 8、11、17 |
说明:
- LTS 表示长期支持版本。
- 企业项目更倾向选择 LTS 版本,因为稳定周期更长。
- 学习阶段不建议一开始纠结版本,先用 JDK 21 或 JDK 25 即可。
2. 安装步骤
Windows 安装流程
- 下载 JDK 安装包
- 安装到指定目录,例如:
text
C:\Program Files\Java\jdk-25
- 配置环境变量:
text
JAVA_HOME=C:\Program Files\Java\jdk-25
Path=%JAVA_HOME%\bin
- 检查安装:
bash
java -version
javac -version
看到版本号说明安装成功。
3. 推荐开发工具
| 工具 | 说明 |
|---|---|
| IntelliJ IDEA | Java 开发首选 IDE,适合 Spring Boot 项目 |
| Eclipse | 老牌 Java IDE |
| VS Code | 可用于简单 Java 学习,但大型项目不如 IDEA |
| DataGrip | 数据库管理工具 |
| Navicat | 数据库可视化工具 |
| Postman | 接口测试工具 |
| Apifox | 接口文档、调试、Mock 一体化工具 |
| Git | 版本控制 |
| Maven / Gradle | 项目构建和依赖管理 |
五、Java 程序执行流程
Java 代码不是直接运行的,而是先编译成字节码,再由 JVM 执行。
text
HelloWorld.java 源代码
↓ javac 编译
HelloWorld.class 字节码
↓ JVM 执行
程序运行
示例:
java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello Java");
}
}
编译:
bash
javac HelloWorld.java
运行:
bash
java HelloWorld
main 方法说明
java
public static void main(String[] args)
含义:
| 关键字 | 说明 |
|---|---|
| public | 公共访问权限 |
| static | 静态方法,不需要创建对象即可调用 |
| void | 没有返回值 |
| main | 程序入口方法名 |
| String\[\] args | 命令行参数 |
六、Java 基础语法
1. 注释
java
// 单行注释
/*
多行注释
*/
/**
* 文档注释
*/
2. 变量
变量是用来存储数据的容器。
java
int age = 18;
String name = "张三";
double price = 99.9;
boolean isLogin = true;
3. 常量
Java 使用 final 定义常量。
java
final double PI = 3.1415926;
常量一般使用大写命名:
java
final int MAX_COUNT = 100;
4. 基本数据类型
Java 有 8 种基本数据类型。
| 类型 | 占用空间 | 默认值 | 示例 | 说明 |
|---|---|---|---|---|
| byte | 1 字节 | 0 | byte b = 10; |
小整数 |
| short | 2 字节 | 0 | short s = 100; |
短整数 |
| int | 4 字节 | 0 | int age = 18; |
常用整数 |
| long | 8 字节 | 0L | long id = 100L; |
长整数 |
| float | 4 字节 | 0.0F | float f = 3.14F; |
单精度小数 |
| double | 8 字节 | 0.0D | double d = 3.14; |
双精度小数 |
| char | 2 字节 | '\u0000' | char c = 'A'; |
字符 |
| boolean | 依 JVM 而定 | false | boolean ok = true; |
布尔值 |
5. 引用数据类型
引用类型包括:
- 类
- 接口
- 数组
- 枚举
- 注解
- String
- 集合对象
示例:
java
String username = "admin";
User user = new User();
int[] nums = {1, 2, 3};
6. 运算符
算术运算符
java
int a = 10;
int b = 3;
System.out.println(a + b); // 13
System.out.println(a - b); // 7
System.out.println(a * b); // 30
System.out.println(a / b); // 3
System.out.println(a % b); // 1
比较运算符
java
System.out.println(a > b);
System.out.println(a >= b);
System.out.println(a < b);
System.out.println(a == b);
System.out.println(a != b);
逻辑运算符
java
boolean x = true;
boolean y = false;
System.out.println(x && y); // false
System.out.println(x || y); // true
System.out.println(!x); // false
7. 条件判断
java
int score = 85;
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
8. switch
java
int type = 2;
switch (type) {
case 1:
System.out.println("普通用户");
break;
case 2:
System.out.println("管理员");
break;
default:
System.out.println("未知角色");
}
较新版本 Java 支持更简洁的 switch 表达式:
java
String role = switch (type) {
case 1 -> "普通用户";
case 2 -> "管理员";
default -> "未知角色";
};
9. 循环
for 循环
java
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
while 循环
java
int i = 0;
while (i < 5) {
System.out.println(i);
i++;
}
do-while 循环
java
int num = 0;
do {
System.out.println(num);
num++;
} while (num < 5);
增强 for 循环
java
int[] arr = {1, 2, 3};
for (int item : arr) {
System.out.println(item);
}
10. break 和 continue
java
for (int i = 0; i < 10; i++) {
if (i == 5) {
break;
}
System.out.println(i);
}
break:结束整个循环。
java
for (int i = 0; i < 10; i++) {
if (i == 5) {
continue;
}
System.out.println(i);
}
continue:跳过本次循环,继续下一次循环。
七、方法、数组与字符串
1. 方法定义
java
public static int add(int a, int b) {
return a + b;
}
调用:
java
int result = add(10, 20);
System.out.println(result);
2. 方法重载
同一个类中,方法名相同,参数列表不同,叫方法重载。
java
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
3. 数组
java
int[] nums = {10, 20, 30};
System.out.println(nums[0]);
System.out.println(nums.length);
遍历数组:
java
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
二维数组:
java
int[][] matrix = {
{1, 2, 3},
{4, 5, 6}
};
System.out.println(matrix[0][1]); // 2
4. String 字符串
java
String str = "hello java";
System.out.println(str.length());
System.out.println(str.toUpperCase());
System.out.println(str.contains("java"));
System.out.println(str.replace("java", "spring"));
字符串比较:
java
String a = "abc";
String b = new String("abc");
System.out.println(a == b); // false,比较地址
System.out.println(a.equals(b)); // true,比较内容
实际项目中,字符串内容比较用:
java
"admin".equals(username)
这样可以避免 username 为 null 导致空指针异常。
5. StringBuilder
适合大量字符串拼接。
java
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("Java");
System.out.println(sb.toString());
八、面向对象编程 OOP
Java 的核心是面向对象。面向对象的四大基础思想:
- 类和对象
- 封装
- 继承
- 多态
1. 类和对象
类是模板,对象是具体实例。
java
public class User {
String username;
int age;
public void sayHello() {
System.out.println("你好,我是" + username);
}
}
创建对象:
java
User user = new User();
user.username = "admin";
user.age = 20;
user.sayHello();
2. 构造方法
构造方法用于创建对象时初始化属性。
java
public class User {
private String username;
private int age;
public User(String username, int age) {
this.username = username;
this.age = age;
}
}
3. this 关键字
this 表示当前对象。
java
public void setUsername(String username) {
this.username = username;
}
4. 封装
封装是把属性私有化,通过 getter/setter 控制访问。
java
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能小于0");
}
this.age = age;
}
}
封装的好处:
- 数据更安全
- 控制访问规则
- 降低外部依赖
- 方便后期维护
5. 继承
继承用于复用父类代码。
java
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("狗叫");
}
}
使用:
java
Dog dog = new Dog();
dog.eat();
dog.bark();
6. 方法重写
子类重写父类方法。
java
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
7. 多态
父类引用指向子类对象。
java
Animal animal = new Cat();
animal.eat();
多态的好处:
- 提高扩展性
- 降低耦合
- 支持面向接口编程
- 适合框架和业务抽象
8. 抽象类
抽象类不能直接创建对象,适合定义通用模板。
java
public abstract class Shape {
public abstract double area();
public void print() {
System.out.println("图形面积:" + area());
}
}
子类实现:
java
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
9. 接口
接口定义能力和规范。
java
public interface PayService {
void pay(BigDecimal amount);
}
实现类:
java
public class AliPayService implements PayService {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付:" + amount);
}
}
实际项目中常见写法:
java
public interface UserService {
User getById(Long id);
}
@Service
public class UserServiceImpl implements UserService {
@Override
public User getById(Long id) {
return new User();
}
}
10. 接口和抽象类区别
| 对比 | 接口 | 抽象类 |
|---|---|---|
| 设计目的 | 定义能力规范 | 抽取共性模板 |
| 继承数量 | 一个类可实现多个接口 | 一个类只能继承一个抽象类 |
| 成员变量 | 默认 public static final | 可以有普通成员变量 |
| 方法 | 抽象方法、默认方法、静态方法 | 抽象方法、普通方法 |
| 使用场景 | 支付接口、通知接口、业务服务接口 | 模板方法、公共父类 |
九、常用 API 与工具类
1. Object 类
所有类默认继承 Object。
常用方法:
| 方法 | 说明 |
|---|---|
toString() |
对象字符串表示 |
equals() |
判断对象是否相等 |
hashCode() |
返回对象哈希值 |
getClass() |
获取对象 Class 信息 |
2. Math
java
System.out.println(Math.max(10, 20));
System.out.println(Math.min(10, 20));
System.out.println(Math.sqrt(16));
System.out.println(Math.random());
3. BigDecimal
金额计算不要使用 double,推荐 BigDecimal。
java
BigDecimal price = new BigDecimal("99.90");
BigDecimal count = new BigDecimal("3");
BigDecimal total = price.multiply(count);
System.out.println(total);
4. LocalDate、LocalDateTime
java
LocalDate today = LocalDate.now();
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(now.format(formatter));
5. UUID
java
String id = UUID.randomUUID().toString();
System.out.println(id);
常用于生成唯一标识。
十、集合框架
Java 集合用于存储多个对象,比数组更灵活。
主要接口:
text
Collection
├── List
├── Set
└── Queue
Map
├── HashMap
├── TreeMap
└── ConcurrentHashMap
1. List
特点:有序、可重复。
java
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Spring");
list.add("MySQL");
System.out.println(list.get(0));
常见实现:
| 实现类 | 特点 |
|---|---|
| ArrayList | 基于数组,查询快,尾部新增快 |
| LinkedList | 基于链表,插入删除较灵活 |
| Vector | 线程安全,较老,不常用 |
2. Set
特点:不可重复。
java
Set<String> set = new HashSet<>();
set.add("Java");
set.add("Java");
set.add("Spring");
System.out.println(set);
常见实现:
| 实现类 | 特点 |
|---|---|
| HashSet | 无序,去重 |
| LinkedHashSet | 保持插入顺序 |
| TreeSet | 可排序 |
3. Map
键值对结构。
java
Map<String, Object> map = new HashMap<>();
map.put("username", "admin");
map.put("age", 20);
System.out.println(map.get("username"));
遍历:
java
for (Map.Entry<String, Object> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
常见实现:
| 实现类 | 特点 |
|---|---|
| HashMap | 常用,线程不安全 |
| LinkedHashMap | 保持插入顺序 |
| TreeMap | 按 key 排序 |
| Hashtable | 线程安全,较老 |
| ConcurrentHashMap | 并发场景常用 |
4. ArrayList 和 LinkedList 区别
| 对比 | ArrayList | LinkedList |
|---|---|---|
| 底层结构 | 动态数组 | 双向链表 |
| 查询 | 快 | 慢 |
| 头部插入删除 | 慢 | 快 |
| 随机访问 | 支持 | 不适合 |
| 使用场景 | 查询多 | 插入删除多 |
5. HashMap 底层原理
HashMap 底层主要由:
text
数组 + 链表 + 红黑树
组成。
基本流程:
- 根据 key 的 hashCode 计算 hash 值
- 根据 hash 值定位数组下标
- 如果该位置没有元素,直接放入
- 如果有元素,比较 key 是否相同
- 如果 key 相同,覆盖 value
- 如果 key 不同,形成链表或红黑树
- 当链表长度较长且数组容量达到条件时,链表可能转为红黑树
十一、泛型
泛型可以让代码更安全、更通用。
1. 泛型集合
java
List<String> names = new ArrayList<>();
names.add("张三");
// names.add(123); // 编译报错
2. 泛型类
java
public class Result<T> {
private Integer code;
private String message;
private T data;
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
}
使用:
java
Result<String> result = new Result<>(200, "成功", "登录成功");
Result<User> userResult = new Result<>(200, "成功", new User());
3. 泛型方法
java
public static <T> T getFirst(List<T> list) {
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
4. 通配符
java
public void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
上界:
java
public void printNumbers(List<? extends Number> list) {
for (Number number : list) {
System.out.println(number);
}
}
下界:
java
public void addInteger(List<? super Integer> list) {
list.add(1);
}
十二、异常处理
异常用于处理程序运行中的错误。
1. 异常体系
text
Throwable
├── Error
└── Exception
├── RuntimeException
└── Checked Exception
| 类型 | 说明 |
|---|---|
| Error | 严重错误,例如 OOM、StackOverflowError |
| Checked Exception | 编译期异常,必须处理 |
| RuntimeException | 运行时异常,可选择处理 |
2. try-catch
java
try {
int result = 10 / 0;
System.out.println(result);
} catch (ArithmeticException e) {
System.out.println("计算异常:" + e.getMessage());
} catch (Exception e) {
System.out.println("系统异常:" + e.getMessage());
}
3. finally
java
try {
System.out.println("执行代码");
} catch (Exception e) {
System.out.println("捕获异常");
} finally {
System.out.println("释放资源");
}
4. throw 和 throws
throw:主动抛出异常。
java
throw new RuntimeException("用户名不能为空");
throws:声明方法可能抛出异常。
java
public void readFile() throws IOException {
FileReader reader = new FileReader("test.txt");
}
5. 自定义业务异常
java
public class BusinessException extends RuntimeException {
public BusinessException(String message) {
super(message);
}
}
使用:
java
if (user == null) {
throw new BusinessException("用户不存在");
}
6. Spring Boot 全局异常处理
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
return Result.fail(e.getMessage());
}
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
return Result.fail("系统异常,请稍后再试");
}
}
十三、IO、NIO 与文件操作
1. 字节流
适合处理图片、视频、压缩包等二进制文件。
java
try (FileInputStream fis = new FileInputStream("input.txt")) {
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
2. 字符流
适合处理文本文件。
java
try (FileReader reader = new FileReader("input.txt")) {
int data;
while ((data = reader.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
3. BufferedReader
java
try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
4. Files 工具类
java
Path path = Paths.get("test.txt");
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
for (String line : lines) {
System.out.println(line);
}
写入文件:
java
Files.writeString(
Paths.get("output.txt"),
"Hello Java",
StandardCharsets.UTF_8
);
十四、Lambda、Stream API 与 Optional
1. Lambda 表达式
Lambda 可以简化函数式接口写法。
传统写法:
java
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行");
}
});
Lambda 写法:
java
Thread thread = new Thread(() -> System.out.println("线程执行"));
2. Stream API
适合集合过滤、转换、排序、分组。
java
List<User> users = List.of(
new User("张三", 18),
new User("李四", 25),
new User("王五", 30)
);
List<User> result = users.stream()
.filter(user -> user.getAge() >= 20)
.toList();
3. map 转换
java
List<String> names = users.stream()
.map(User::getUsername)
.toList();
4. 排序
java
List<User> sortedUsers = users.stream()
.sorted(Comparator.comparing(User::getAge))
.toList();
5. 分组
java
Map<Integer, List<User>> groupMap = users.stream()
.collect(Collectors.groupingBy(User::getAge));
6. Optional
用于减少空指针异常。
java
Optional<User> optionalUser = Optional.ofNullable(user);
String username = optionalUser
.map(User::getUsername)
.orElse("默认用户");
十五、多线程与并发编程
1. 创建线程
继承 Thread
java
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行");
}
}
java
new MyThread().start();
实现 Runnable
java
Runnable runnable = () -> System.out.println("Runnable 执行");
new Thread(runnable).start();
实现 Callable
java
Callable<String> callable = () -> "任务结果";
FutureTask<String> task = new FutureTask<>(callable);
new Thread(task).start();
String result = task.get();
2. 线程生命周期
text
NEW 新建
RUNNABLE 就绪/运行
BLOCKED 阻塞
WAITING 等待
TIMED_WAITING 限时等待
TERMINATED 结束
3. synchronized
java
public synchronized void add() {
count++;
}
也可以锁代码块:
java
synchronized (this) {
count++;
}
4. volatile
volatile 可以保证变量的可见性,不能保证复合操作的原子性。
java
private volatile boolean running = true;
5. ReentrantLock
java
private final ReentrantLock lock = new ReentrantLock();
public void add() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
6. 线程池
项目中不建议频繁 new Thread,推荐使用线程池。
java
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> {
System.out.println("执行任务");
});
executor.shutdown();
更推荐手动创建 ThreadPoolExecutor:
java
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5,
10,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
7. 线程池核心参数
| 参数 | 说明 |
|---|---|
| corePoolSize | 核心线程数 |
| maximumPoolSize | 最大线程数 |
| keepAliveTime | 空闲线程存活时间 |
| unit | 时间单位 |
| workQueue | 任务队列 |
| threadFactory | 线程工厂 |
| handler | 拒绝策略 |
8. CompletableFuture
适合异步编排。
java
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "查询用户信息";
});
String result = future.get();
组合任务:
java
CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> "用户信息");
CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> "订单信息");
CompletableFuture<Void> all = CompletableFuture.allOf(userFuture, orderFuture);
all.join();
十六、JVM 核心原理
1. JVM 是什么?
JVM 是 Java 虚拟机,负责运行 Java 字节码。
Java 跨平台的核心原因:
text
同一份 Java 字节码,可以运行在不同操作系统对应的 JVM 上。
2. JVM 内存结构
| 区域 | 线程是否共享 | 作用 |
|---|---|---|
| 程序计数器 | 线程私有 | 记录当前线程执行位置 |
| Java 虚拟机栈 | 线程私有 | 存储方法调用栈、局部变量 |
| 本地方法栈 | 线程私有 | Native 方法调用 |
| 堆 | 线程共享 | 存储对象实例 |
| 方法区 / 元空间 | 线程共享 | 存储类信息、常量、静态变量等 |
3. 对象创建过程
java
User user = new User();
大致过程:
- 类加载检查
- 分配内存
- 初始化零值
- 设置对象头
- 执行构造方法
- 引用指向对象
4. 类加载机制
类加载过程:
text
加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
5. 双亲委派模型
类加载器收到加载请求后,先交给父加载器尝试加载,父加载器无法加载时,子加载器再加载。
好处:
- 避免核心类被篡改
- 避免类重复加载
- 保证 Java 核心 API 安全
6. 垃圾回收 GC
Java 会自动回收不再使用的对象。
判断对象是否可回收:
- 引用计数法
- 可达性分析算法
Java 主流使用可达性分析。
7. GC Roots 常见对象
- 虚拟机栈中的引用对象
- 方法区中的静态属性引用对象
- 方法区中的常量引用对象
- 本地方法栈 JNI 引用对象
- 活跃线程引用对象
8. 常见 GC 算法
| 算法 | 说明 |
|---|---|
| 标记-清除 | 标记垃圾对象后清除,会产生内存碎片 |
| 标记-整理 | 清除后整理内存,减少碎片 |
| 复制算法 | 将存活对象复制到另一块区域 |
| 分代收集 | 新生代、老年代使用不同回收策略 |
9. 常见 JVM 参数
| 参数 | 说明 |
|---|---|
-Xms |
初始堆大小 |
-Xmx |
最大堆大小 |
-Xss |
每个线程栈大小 |
-XX:+UseG1GC |
使用 G1 垃圾回收器 |
-XX:+HeapDumpOnOutOfMemoryError |
OOM 时导出堆快照 |
-XX:HeapDumpPath |
堆快照输出路径 |
示例:
bash
java -Xms512m -Xmx1024m -XX:+UseG1GC -jar app.jar
十七、数据库与 MySQL
Java 后端开发必须掌握数据库。
1. SQL 基础
查询
sql
SELECT id, username, age FROM user WHERE id = 1;
新增
sql
INSERT INTO user(username, password, age) VALUES('admin', '123456', 20);
修改
sql
UPDATE user SET username = 'newAdmin' WHERE id = 1;
删除
sql
DELETE FROM user WHERE id = 1;
2. 表设计示例
sql
CREATE TABLE user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL,
nickname VARCHAR(50),
email VARCHAR(100),
status TINYINT DEFAULT 1,
create_time DATETIME,
update_time DATETIME
);
3. 索引
sql
CREATE INDEX idx_username ON user(username);
索引优点:
- 提升查询速度
- 支持排序优化
- 支持唯一约束
索引缺点:
- 占用空间
- 降低新增、修改、删除速度
- 不合理索引会影响性能
4. 事务
事务保证一组操作要么全部成功,要么全部失败。
ACID:
| 特性 | 说明 |
|---|---|
| Atomicity 原子性 | 要么全部成功,要么全部失败 |
| Consistency 一致性 | 数据从一个一致状态到另一个一致状态 |
| Isolation 隔离性 | 并发事务之间互不干扰 |
| Durability 持久性 | 提交后数据永久保存 |
十八、JDBC、MyBatis、MyBatis-Plus、JPA
1. JDBC
JDBC 是 Java 操作数据库的基础 API。
java
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/demo",
"root",
"123456"
);
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE id = ?");
ps.setLong(1, 1L);
ResultSet rs = ps.executeQuery();
实际项目中不会大量手写 JDBC,通常使用 MyBatis、MyBatis-Plus 或 JPA。
2. MyBatis
Mapper 接口:
java
@Mapper
public interface UserMapper {
User selectById(Long id);
}
XML:
xml
<select id="selectById" resultType="com.example.entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
3. MyBatis-Plus
Mapper:
java
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
查询:
java
User user = userMapper.selectById(1L);
条件查询:
java
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getUsername, "admin");
User user = userMapper.selectOne(wrapper);
4. JPA / Hibernate
实体类:
java
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
}
Repository:
java
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
5. MyBatis 和 JPA 区别
| 对比 | MyBatis | JPA/Hibernate |
|---|---|---|
| SQL 控制 | 强,手写 SQL 灵活 | 自动生成 SQL 较多 |
| 学习成本 | 中等 | 较高 |
| 复杂查询 | 适合 | 需要理解 ORM 机制 |
| 国内项目 | 非常常见 | 部分项目使用 |
| 适合场景 | 复杂业务、SQL 优化 | 领域模型清晰、CRUD 较多 |
十九、Java Web 与 HTTP 基础
1. HTTP 请求方法
| 方法 | 作用 |
|---|---|
| GET | 查询数据 |
| POST | 新增数据、提交表单 |
| PUT | 修改完整数据 |
| PATCH | 修改部分数据 |
| DELETE | 删除数据 |
2. HTTP 状态码
| 状态码 | 说明 |
|---|---|
| 200 | 成功 |
| 201 | 创建成功 |
| 400 | 请求参数错误 |
| 401 | 未登录 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 500 | 服务器异常 |
3. RESTful API 示例
| 操作 | 请求 |
|---|---|
| 查询用户列表 | GET /users |
| 查询单个用户 | GET /users/{id} |
| 新增用户 | POST /users |
| 修改用户 | PUT /users/{id} |
| 删除用户 | DELETE /users/{id} |
4. Servlet
Servlet 是 Java Web 的底层基础。
java
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.getWriter().write("Hello Servlet");
}
}
现在企业开发一般不直接写 Servlet,而是使用 Spring MVC / Spring Boot。
二十、Spring、Spring MVC、Spring Boot
1. Spring 核心思想
Spring 的核心:
- IOC:控制反转
- DI:依赖注入
- AOP:面向切面编程
2. IOC 和 DI
传统写法:
java
UserService userService = new UserServiceImpl();
Spring 写法:
java
@Service
public class UserServiceImpl implements UserService {
}
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
}
对象由 Spring 容器创建和管理。
3. AOP
AOP 适合处理横切逻辑:
- 日志记录
- 权限校验
- 事务控制
- 接口耗时统计
- 统一异常处理
示例:
java
@Aspect
@Component
public class LogAspect {
@Around("execution(* com.example.controller..*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println("接口耗时:" + (end - start) + "ms");
return result;
}
}
4. Spring Boot 项目结构
text
src
└── main
├── java
│ └── com.example.demo
│ ├── DemoApplication.java
│ ├── controller
│ ├── service
│ ├── service.impl
│ ├── mapper
│ ├── entity
│ ├── dto
│ ├── vo
│ ├── config
│ ├── common
│ └── exception
└── resources
├── application.yml
└── mapper
5. Spring Boot 启动类
java
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
6. Controller
java
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public Result<UserVO> getUser(@PathVariable Long id) {
return Result.success(userService.getUser(id));
}
}
7. Service
java
public interface UserService {
UserVO getUser(Long id);
}
java
@Service
public class UserServiceImpl implements UserService {
@Override
public UserVO getUser(Long id) {
return new UserVO();
}
}
8. 配置文件 application.yml
yaml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
9. 统一返回结果
java
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("成功");
result.setData(data);
return result;
}
public static <T> Result<T> fail(String message) {
Result<T> result = new Result<>();
result.setCode(500);
result.setMessage(message);
return result;
}
}
10. 参数校验
DTO:
java
@Data
public class LoginDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
}
Controller:
java
@PostMapping("/login")
public Result<String> login(@Valid @RequestBody LoginDTO loginDTO) {
return Result.success("登录成功");
}
二十一、登录注册、JWT、权限拦截
1. 登录流程
text
1. 前端输入用户名和密码
2. 调用后端 /login 接口
3. 后端查询用户是否存在
4. 校验密码是否正确
5. 登录成功生成 JWT Token
6. 前端保存 token
7. 后续请求在 Authorization 请求头携带 token
8. 后端拦截器或过滤器校验 token
9. 校验通过访问接口,否则返回 401
2. 登录接口示例
java
@PostMapping("/login")
public Result<String> login(@Valid @RequestBody LoginDTO loginDTO) {
String token = userService.login(loginDTO);
return Result.success(token);
}
3. 前端携带 Token
javascript
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = 'Bearer ' + token
}
return config
})
4. 后端拦截器
java
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String authorization = request.getHeader("Authorization");
if (authorization == null || !authorization.startsWith("Bearer ")) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
String token = authorization.substring(7);
// 校验 token
return true;
}
}
5. 注册拦截器
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register");
}
}
6. 权限模型
常见权限模型:
text
用户 User
角色 Role
权限 Permission
关系:
text
一个用户可以有多个角色
一个角色可以有多个权限
常见表:
- user
- role
- permission
- user_role
- role_permission
二十二、Redis、消息队列、搜索、缓存
1. Redis
Redis 常用场景:
- 登录 token 存储
- 验证码缓存
- 热点数据缓存
- 分布式锁
- 排行榜
- 限流
- 会话共享
Spring Boot 使用 Redis:
java
@Resource
private StringRedisTemplate stringRedisTemplate;
public void saveCode(String phone, String code) {
stringRedisTemplate.opsForValue().set("code:" + phone, code, 5, TimeUnit.MINUTES);
}
2. 缓存穿透、击穿、雪崩
| 问题 | 说明 | 解决方案 |
|---|---|---|
| 缓存穿透 | 查询不存在的数据,绕过缓存打到数据库 | 缓存空值、布隆过滤器 |
| 缓存击穿 | 热点 key 失效,大量请求打到数据库 | 互斥锁、逻辑过期 |
| 缓存雪崩 | 大量 key 同时失效 | 过期时间随机化、限流、降级 |
3. 消息队列 MQ
常见 MQ:
- RabbitMQ
- Kafka
- RocketMQ
应用场景:
- 异步处理
- 削峰填谷
- 订单超时取消
- 日志收集
- 系统解耦
4. Elasticsearch
适合搜索场景:
- 商品搜索
- 文章搜索
- 日志搜索
- 后台模糊查询
二十三、Maven、Gradle 与项目构建
1. Maven 是什么?
Maven 用于:
- 管理依赖
- 编译项目
- 运行测试
- 打包项目
- 管理项目结构
2. pom.xml 示例
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
3. Maven 常用命令
| 命令 | 作用 |
|---|---|
mvn clean |
清理构建文件 |
mvn compile |
编译源码 |
mvn test |
运行测试 |
mvn package |
打包 |
mvn install |
安装到本地仓库 |
mvn spring-boot:run |
启动 Spring Boot 项目 |
4. Gradle 简介
Gradle 也是构建工具,常用于 Java、Kotlin、Android 项目。
build.gradle 示例:
groovy
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.14'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
二十四、Docker、Linux、Nginx 部署
1. Spring Boot 打包
bash
mvn clean package
生成:
text
target/demo-0.0.1-SNAPSHOT.jar
启动:
bash
java -jar demo-0.0.1-SNAPSHOT.jar
后台启动:
bash
nohup java -jar demo.jar > app.log 2>&1 &
2. Dockerfile
dockerfile
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/demo.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
构建镜像:
bash
docker build -t demo-app .
运行容器:
bash
docker run -d -p 8080:8080 --name demo demo-app
3. Nginx 反向代理
nginx
server {
listen 80;
server_name example.com;
location /api/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root /www/wwwroot/frontend;
index index.html;
try_files $uri $uri/ /index.html;
}
}
4. 前后端分离部署结构
text
用户浏览器
↓
Nginx
├── / → Vue/React 静态文件
└── /api → Spring Boot 8080
↓
MySQL / Redis
二十五、Java 企业级项目结构
推荐结构:
text
mall-admin
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com.example.mall
│ │ │ ├── MallApplication.java
│ │ │ ├── common
│ │ │ │ ├── Result.java
│ │ │ │ └── PageResult.java
│ │ │ ├── config
│ │ │ ├── controller
│ │ │ ├── service
│ │ │ ├── service.impl
│ │ │ ├── mapper
│ │ │ ├── entity
│ │ │ ├── dto
│ │ │ ├── vo
│ │ │ ├── exception
│ │ │ ├── interceptor
│ │ │ └── utils
│ │ └── resources
│ │ ├── application.yml
│ │ └── mapper
│ └── test
└── README.md
目录说明:
| 目录 | 作用 |
|---|---|
| common | 公共返回对象、常量、分页对象 |
| config | 配置类,如跨域、拦截器、Redis |
| controller | 接口控制层 |
| service | 业务接口 |
| service.impl | 业务实现 |
| mapper | 数据库访问层 |
| entity | 数据库实体类 |
| dto | 接收前端参数 |
| vo | 返回前端视图对象 |
| exception | 异常处理 |
| interceptor | 登录拦截器 |
| utils | 工具类 |
二十六、Java 学习路线
阶段 1:Java 基础
学习重点:
- 环境安装
- 基础语法
- 数据类型
- 运算符
- 流程控制
- 数组
- 方法
- 类和对象
- 封装、继承、多态
- 接口、抽象类
目标:能独立写控制台小程序。
阶段 2:Java 进阶
学习重点:
- String
- 集合框架
- 泛型
- 异常
- IO
- Lambda
- Stream
- Optional
- 反射
- 注解
- 枚举
- 多线程
目标:理解 Java 常用 API 和基础底层思想。
阶段 3:数据库
学习重点:
- MySQL 基础
- SQL 查询
- 表设计
- 索引
- 事务
- JDBC
- MyBatis
- MyBatis-Plus
目标:能完成用户、商品、订单等表的增删改查。
阶段 4:Spring Boot
学习重点:
- Spring IOC
- Spring AOP
- Spring MVC
- Spring Boot
- RESTful API
- 参数校验
- 全局异常
- 统一返回
- 文件上传
- 登录注册
- JWT 权限
目标:能写完整后端接口。
阶段 5:前后端分离项目
推荐做:
- 登录注册系统
- 用户管理系统
- 权限管理系统
- 博客系统
- 商品管理系统
- 后台管理系统
目标:完成 Vue/React + Spring Boot + MySQL 项目。
阶段 6:企业进阶
学习重点:
- Redis
- MQ
- Elasticsearch
- Docker
- Linux
- Nginx
- Jenkins
- Spring Cloud
- 微服务
- 分布式锁
- 分布式事务
- 高并发优化
目标:具备企业项目开发和面试竞争力。
二十七、Java 官方文档与相关资源表
1. Java 官方资源
| 资源 | 地址 | 用途 |
|---|---|---|
| Oracle Java 下载 | https://www.oracle.com/java/technologies/downloads/ | 下载 JDK |
| Oracle Java 中文下载页 | https://www.oracle.com/tw/java/technologies/downloads/ | 下载 JDK,可查看当前版本 |
| Java SE API 文档 | https://www.oracle.com/java/technologies/java-se-api-doc.html | 查询 Java 标准库 API |
| Oracle Java 文档入口 | https://docs.oracle.com/en/java/ | Java 官方文档 |
| OpenJDK | https://openjdk.org/ | 开源 JDK 项目 |
| OpenJDK JDK 项目 | https://openjdk.org/projects/jdk/ | JDK 版本项目 |
| dev.java | https://dev.java/ | Oracle 提供的 Java 学习入口 |
| Java Language Specification | https://docs.oracle.com/javase/specs/ | Java 语言规范 |
| Java Virtual Machine Specification | https://docs.oracle.com/javase/specs/jvms/se25/html/ | JVM 规范 |
2. Spring 生态官方资源
| 资源 | 地址 | 用途 |
|---|---|---|
| Spring 官网 | https://spring.io/ | Spring 生态入口 |
| Spring Framework | https://spring.io/projects/spring-framework | Spring 核心框架 |
| Spring Framework Docs | https://docs.spring.io/spring-framework/reference/ | Spring 参考文档 |
| Spring Boot | https://spring.io/projects/spring-boot | Spring Boot 项目页 |
| Spring Boot Docs | https://docs.spring.io/spring-boot/index.html | Spring Boot 文档 |
| Spring Security | https://spring.io/projects/spring-security | 权限安全框架 |
| Spring Security Docs | https://docs.spring.io/spring-security/reference/ | 安全认证文档 |
| Spring Initializr | https://start.spring.io/ | 在线创建 Spring Boot 项目 |
| Spring Guides | https://spring.io/guides | Spring 官方教程 |
3. 数据库与 ORM 资源
| 资源 | 地址 | 用途 |
|---|---|---|
| MySQL 文档 | https://dev.mysql.com/doc/ | MySQL 官方文档 |
| MyBatis | https://mybatis.org/mybatis-3/ | MyBatis 官方文档 |
| MyBatis-Spring-Boot | https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/ | MyBatis Spring Boot 集成 |
| MyBatis-Plus | https://baomidou.com/ | MyBatis-Plus 官方文档 |
| Hibernate ORM | https://hibernate.org/orm/documentation/ | Hibernate ORM 文档 |
4. 构建、部署与运维资源
| 资源 | 地址 | 用途 |
|---|---|---|
| Maven | https://maven.apache.org/guides/index.html | Maven 官方指南 |
| Maven Getting Started | https://maven.apache.org/guides/getting-started/ | Maven 入门 |
| Gradle Docs | https://docs.gradle.org/ | Gradle 官方文档 |
| Docker Docs | https://docs.docker.com/ | Docker 官方文档 |
| Redis Docs | https://redis.io/docs/latest/ | Redis 官方文档 |
| Nginx Docs | https://nginx.org/en/docs/ | Nginx 官方文档 |
| Kubernetes Docs | https://kubernetes.io/docs/home/ | K8s 官方文档 |
5. 接口、测试与工具资源
| 工具 | 地址 | 用途 |
|---|---|---|
| Postman | https://www.postman.com/ | API 调试 |
| Apifox | https://apifox.com/ | API 文档、调试、Mock |
| IntelliJ IDEA | https://www.jetbrains.com/idea/ | Java IDE |
| Git | https://git-scm.com/ | 版本控制 |
| GitHub | https://github.com/ | 代码托管 |
| Gitee | https://gitee.com/ | 国内代码托管 |
| Navicat | https://www.navicat.com/ | 数据库管理 |
| DBeaver | https://dbeaver.io/ | 免费数据库管理工具 |
二十八、Java 面试题与答案
下面整理 80 道 Java 常见面试题,覆盖 Java 基础、集合、JVM、并发、数据库、Spring Boot、Redis、微服务与项目。
一、Java 基础面试题
1. Java 有哪些基本数据类型?
Java 有 8 种基本数据类型:
- byte
- short
- int
- long
- float
- double
- char
- boolean
其中整数默认是 int,小数默认是 double。
2. Java 是值传递还是引用传递?
Java 只有值传递。
如果传递的是基本类型,传递的是值的副本。
如果传递的是对象引用,传递的是引用地址的副本。
所以方法中可以修改对象内部属性,但不能让外部引用指向一个新对象。
3. == 和 equals() 的区别?
==:
- 基本类型比较值
- 引用类型比较内存地址
equals():
- 默认比较地址
- 很多类重写后比较内容,例如 String、Integer
示例:
java
String a = new String("abc");
String b = new String("abc");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
4. String 为什么不可变?
String 内部用于存储字符的数据结构被设计为不可随意修改,同时 String 类本身是 final 类。
不可变的好处:
- 线程安全
- 可以被字符串常量池复用
- 适合作为 HashMap 的 key
- 避免被恶意修改,例如数据库连接地址、文件路径
5. String、StringBuilder、StringBuffer 区别?
| 类型 | 是否可变 | 是否线程安全 | 场景 |
|---|---|---|---|
| String | 不可变 | 安全 | 少量字符串 |
| StringBuilder | 可变 | 不安全 | 单线程大量拼接 |
| StringBuffer | 可变 | 安全 | 多线程拼接 |
实际项目中,单线程拼接优先使用 StringBuilder。
6. final、finally、finalize 区别?
final:修饰类、方法、变量。类不能被继承,方法不能被重写,变量不能重新赋值。finally:异常处理中一定会执行的代码块,常用于释放资源。finalize:Object 的方法,垃圾回收前可能被调用,已经不推荐使用。
7. 抽象类和接口区别?
抽象类适合描述共性模板,接口适合定义能力规范。
一个类只能继承一个抽象类,但可以实现多个接口。
8. 重载和重写区别?
重载 Overload:同一个类中,方法名相同,参数列表不同。
重写 Override:子类重新实现父类方法,方法签名通常相同。
9. static 关键字有什么作用?
static 可以修饰:
- 变量:类变量,所有对象共享
- 方法:类方法,不需要创建对象即可调用
- 代码块:类加载时执行
- 内部类:静态内部类
10. this 和 super 的区别?
this 表示当前对象。
super 表示父类对象。
常见用途:
- this 调用当前类属性、方法、构造器
- super 调用父类属性、方法、构造器
二、集合面试题
11. ArrayList 和 LinkedList 区别?
ArrayList 底层是动态数组,查询快,随机访问快。
LinkedList 底层是双向链表,头尾插入删除较方便,但随机访问慢。
12. ArrayList 扩容机制是什么?
ArrayList 底层数组容量不够时会扩容。常见实现中,新容量通常约为原容量的 1.5 倍,然后把旧数组元素复制到新数组中。
因此,如果能提前知道数据量,建议初始化容量:
java
List<String> list = new ArrayList<>(1000);
13. HashMap 底层结构是什么?
HashMap 底层是:
text
数组 + 链表 + 红黑树
当发生 hash 冲突时,会形成链表;链表过长且数组容量达到一定条件时,会转换为红黑树,提高查询效率。
14. HashMap 为什么线程不安全?
因为多个线程同时 put、resize、修改链表或红黑树时,可能导致数据覆盖、数据丢失、结构异常等问题。
并发场景推荐使用:
java
ConcurrentHashMap
15. HashMap 和 Hashtable 区别?
| 对比 | HashMap | Hashtable |
|---|---|---|
| 线程安全 | 不安全 | 安全 |
| 性能 | 较高 | 较低 |
| null key/value | 允许 | 不允许 |
| 是否推荐 | 推荐单线程使用 | 不推荐新项目使用 |
16. HashMap 和 ConcurrentHashMap 区别?
HashMap 线程不安全,适合单线程。
ConcurrentHashMap 线程安全,适合并发场景。
ConcurrentHashMap 通过更细粒度的并发控制提升性能,不是简单地给整个 Map 加 synchronized。
17. List、Set、Map 区别?
- List:有序、可重复
- Set:不可重复
- Map:键值对结构,key 不可重复
18. 如何实现集合去重?
可以使用 Set:
java
List<String> list = List.of("a", "b", "a");
Set<String> set = new HashSet<>(list);
如果是对象去重,需要重写 equals() 和 hashCode()。
19. Iterator 遍历时能不能删除元素?
可以,但要使用 Iterator 的 remove() 方法,不能直接调用集合的 remove()。
java
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if ("a".equals(item)) {
iterator.remove();
}
}
20. fail-fast 是什么?
fail-fast 是集合遍历时的一种快速失败机制。遍历过程中如果集合结构被非迭代器方式修改,可能抛出 ConcurrentModificationException。
三、异常与泛型面试题
21. Checked Exception 和 RuntimeException 区别?
Checked Exception 是编译期异常,必须处理或声明抛出。
RuntimeException 是运行时异常,可以不强制处理。
22. throw 和 throws 区别?
throw 用于实际抛出异常对象。
throws 用于方法声明,表示该方法可能抛出异常。
23. 泛型有什么作用?
泛型的作用:
- 提高类型安全
- 避免强制类型转换
- 提高代码复用性
- 编译期发现类型错误
24. Java 泛型擦除是什么?
Java 泛型主要在编译期生效,编译后泛型类型信息会被擦除。运行时通常无法直接获取 List<String> 中的 String 泛型类型。
25. List<?>、List<? extends T>、List<? super T> 区别?
List<?>:未知类型,只适合读取 ObjectList<? extends T>:上界通配符,适合读取 T 或其子类List<? super T>:下界通配符,适合写入 T 或其子类
口诀:
PECS:Producer Extends,Consumer Super。
四、JVM 面试题
26. JVM 内存结构有哪些?
主要包括:
- 程序计数器
- Java 虚拟机栈
- 本地方法栈
- 堆
- 方法区 / 元空间
其中堆和方法区是线程共享的,程序计数器、虚拟机栈、本地方法栈是线程私有的。
27. 堆和栈有什么区别?
栈:存储方法调用、局部变量、操作数栈,线程私有,生命周期随方法调用结束。
堆:存储对象实例,线程共享,由 GC 管理。
28. 什么是类加载机制?
类加载机制是 JVM 把 class 文件加载到内存,并完成验证、准备、解析、初始化的过程。
流程:
text
加载 → 验证 → 准备 → 解析 → 初始化
29. 什么是双亲委派模型?
类加载器加载类时,会先委托父加载器加载,父加载器无法加载时,子加载器才尝试加载。
优点:
- 避免类重复加载
- 保护 Java 核心类库
- 提高安全性
30. 如何判断对象是否可以被回收?
Java 主要使用可达性分析算法。
如果对象无法从 GC Roots 通过引用链到达,则认为对象可以被回收。
31. GC Roots 有哪些?
常见 GC Roots:
- 虚拟机栈中的引用对象
- 方法区中的静态变量引用对象
- 方法区中的常量引用对象
- 本地方法栈 JNI 引用对象
- 活跃线程引用对象
32. Minor GC 和 Full GC 区别?
Minor GC:主要回收新生代。
Full GC:通常回收整个堆和方法区,开销更大,停顿时间更长。
33. 什么情况下会发生 OOM?
常见原因:
- 堆内存不足
- 大对象过多
- 内存泄漏
- 线程过多导致栈内存不足
- 元空间加载类过多
34. StackOverflowError 是什么?
栈溢出错误,常见原因是递归过深或方法调用层级过多。
java
public void test() {
test();
}
35. 常见 JVM 调优参数有哪些?
常见参数:
bash
-Xms512m
-Xmx1024m
-Xss1m
-XX:+UseG1GC
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/logs/heapdump.hprof
五、多线程与并发面试题
36. 创建线程有几种方式?
常见方式:
- 继承 Thread
- 实现 Runnable
- 实现 Callable + FutureTask
- 使用线程池
- 使用 CompletableFuture
项目中推荐使用线程池。
37. start() 和 run() 区别?
start() 会启动新线程,由 JVM 调用 run 方法。
run() 只是普通方法调用,不会创建新线程。
38. synchronized 的作用是什么?
synchronized 用于保证线程安全,可以保证同一时刻只有一个线程进入同步代码块,同时具有可见性和互斥性。
39. synchronized 和 ReentrantLock 区别?
| 对比 | synchronized | ReentrantLock |
|---|---|---|
| 类型 | JVM 关键字 | JDK 类 |
| 释放锁 | 自动释放 | 需要手动 unlock |
| 可中断 | 不灵活 | 支持 |
| 公平锁 | 不支持直接设置 | 支持 |
| 条件队列 | 单一等待队列 | 多个 Condition |
40. volatile 有什么作用?
volatile 保证变量的可见性和禁止指令重排序,但不能保证复合操作的原子性。
例如:
java
volatile int count = 0;
count++; // 不是原子操作
41. 什么是死锁?
死锁是多个线程互相持有对方需要的锁,导致所有线程都无法继续执行。
产生条件:
- 互斥条件
- 请求并保持
- 不可剥夺
- 循环等待
42. 如何避免死锁?
- 按固定顺序获取锁
- 设置锁超时时间
- 减少锁粒度
- 避免嵌套锁
- 使用 tryLock
43. 线程池核心参数有哪些?
- corePoolSize
- maximumPoolSize
- keepAliveTime
- unit
- workQueue
- threadFactory
- rejectedExecutionHandler
44. 线程池拒绝策略有哪些?
常见拒绝策略:
- AbortPolicy:抛异常
- CallerRunsPolicy:调用者线程执行
- DiscardPolicy:直接丢弃
- DiscardOldestPolicy:丢弃队列最老任务
45. ThreadLocal 是什么?
ThreadLocal 为每个线程提供独立变量副本,常用于保存用户上下文、请求上下文、数据库连接等。
使用后要注意 remove,避免线程池场景下内存泄漏。
六、数据库与 MyBatis 面试题
46. 什么是事务?
事务是一组数据库操作,要么全部成功,要么全部失败。
47. ACID 是什么?
- 原子性:全部成功或全部失败
- 一致性:数据状态合法
- 隔离性:并发事务互不干扰
- 持久性:提交后永久保存
48. MySQL 隔离级别有哪些?
- 读未提交 Read Uncommitted
- 读已提交 Read Committed
- 可重复读 Repeatable Read
- 串行化 Serializable
49. 脏读、不可重复读、幻读是什么?
脏读:读到其他事务未提交的数据。
不可重复读:同一事务中两次读取同一行数据结果不同。
幻读:同一事务中两次范围查询,结果行数不同。
50. 索引为什么能提高查询速度?
索引可以减少数据库扫描的数据量。MySQL InnoDB 常用 B+ 树索引,可以通过树结构快速定位数据,而不是全表扫描。
51. B+ 树为什么适合做数据库索引?
原因:
- 树高度低,磁盘 IO 少
- 叶子节点有序,适合范围查询
- 非叶子节点只存 key,可以容纳更多索引项
- 查询性能稳定
52. 什么情况下索引会失效?
常见情况:
- 对索引列使用函数
- 使用左模糊 LIKE,例如
%abc - 隐式类型转换
- 联合索引不满足最左前缀
- OR 条件使用不当
- 查询条件选择性太低
53. MyBatis 中 #{} 和 ${} 区别?
#{} 使用预编译,占位符方式,能防 SQL 注入。
${} 是字符串拼接,存在 SQL 注入风险。
一般参数传递使用 #{}。
54. MyBatis 一级缓存和二级缓存区别?
一级缓存:SqlSession 级别,默认开启。
二级缓存:Mapper namespace 级别,需要配置开启。
实际项目中二级缓存使用要谨慎,复杂业务中容易出现数据一致性问题。
55. MyBatis-Plus 的优点是什么?
优点:
- 简化 CRUD
- 减少重复 SQL
- 提供条件构造器
- 支持分页插件
- 支持代码生成
- 与 MyBatis 兼容
七、Spring 与 Spring Boot 面试题
56. 什么是 IOC?
IOC 是控制反转,对象的创建和依赖关系不再由程序员手动控制,而是交给 Spring 容器管理。
57. 什么是 DI?
DI 是依赖注入,Spring 容器把对象依赖自动注入到需要的地方。
常见方式:
- 构造器注入
- Setter 注入
- 字段注入
推荐构造器注入。
58. 什么是 AOP?
AOP 是面向切面编程,用于把日志、权限、事务、耗时统计等横切逻辑从业务代码中抽离出来。
59. Spring Bean 生命周期是什么?
大致流程:
- 实例化 Bean
- 属性赋值
- Aware 回调
- BeanPostProcessor 前置处理
- 初始化方法
- BeanPostProcessor 后置处理
- Bean 可使用
- 容器关闭时销毁 Bean
60. Spring 如何解决循环依赖?
Spring 通过三级缓存解决单例 Bean 的部分循环依赖。
但构造器循环依赖无法解决,因为对象还没创建完成就互相依赖。
61. Spring MVC 请求流程是什么?
流程:
text
请求 → DispatcherServlet → HandlerMapping → HandlerAdapter → Controller → Service → 返回结果 → 视图/JSON响应
62. Spring Boot 自动配置原理是什么?
Spring Boot 根据 classpath 中的依赖、配置属性和条件注解自动装配 Bean,减少手动配置。
核心思想:
- Starter 依赖
- 自动配置类
- 条件注解
- 配置属性绑定
63. Spring Boot 常用注解有哪些?
常见注解:
@SpringBootApplication@RestController@RequestMapping@GetMapping@PostMapping@Service@Repository@Component@Autowired@Configuration@Bean@Transactional@Valid
64. @Autowired 和 @Resource 区别?
@Autowired 默认按类型注入,属于 Spring。
@Resource 默认按名称注入,属于 Jakarta/Java 标准注解。
65. @Transactional 什么时候会失效?
常见失效场景:
- 方法不是 public
- 同类内部方法调用
- 异常被 catch 但未抛出
- 抛出的异常类型不触发回滚
- 数据库引擎不支持事务
- 没有被 Spring 管理
66. Spring Boot 如何统一异常处理?
使用:
java
@RestControllerAdvice
@ExceptionHandler
示例:
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result<Void> handle(Exception e) {
return Result.fail(e.getMessage());
}
}
67. Spring Boot 如何解决跨域?
可以使用 WebMvcConfigurer:
java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
生产环境不建议直接放开所有来源,应指定具体域名。
68. 拦截器和过滤器区别?
过滤器 Filter 属于 Servlet 规范,执行时机更靠前。
拦截器 Interceptor 属于 Spring MVC,主要拦截 Controller 请求。
常见顺序:
text
Filter → Interceptor → Controller
八、登录认证与安全面试题
69. JWT 是什么?
JWT 是一种令牌格式,常用于前后端分离登录认证。
它通常由 Header、Payload、Signature 三部分组成。
70. JWT 登录流程是什么?
- 用户登录提交账号密码
- 后端校验成功后生成 JWT
- 前端保存 JWT
- 请求接口时在请求头携带 JWT
- 后端解析和校验 JWT
- 校验成功放行,请求失败返回 401
71. Token 存在哪里?
常见方案:
- localStorage:简单,但容易受 XSS 影响
- sessionStorage:关闭页面失效
- HttpOnly Cookie:前端 JS 不能直接读取,安全性更好
- Redis:服务端保存 token 状态,便于踢下线和过期控制
72. 什么是 RBAC 权限模型?
RBAC 是基于角色的访问控制。
模型:
text
用户 → 角色 → 权限
例如:
- 用户 A 拥有管理员角色
- 管理员角色拥有用户管理、菜单管理权限
九、Redis 与缓存面试题
73. Redis 常用数据类型有哪些?
- String
- Hash
- List
- Set
- ZSet
- Stream
- Bitmap
- HyperLogLog
- Geo
74. Redis 常见应用场景有哪些?
- 缓存
- 分布式锁
- 验证码
- 排行榜
- 限流
- 购物车
- 会话共享
- 消息队列
75. 缓存穿透、击穿、雪崩区别?
缓存穿透:查询不存在数据,缓存没有,数据库也没有。
缓存击穿:热点 key 过期,大量请求打到数据库。
缓存雪崩:大量 key 同时失效,数据库压力暴增。
76. Redis 分布式锁如何实现?
常见命令:
bash
SET lock_key unique_value NX EX 30
含义:
- NX:不存在才设置
- EX:设置过期时间
- unique_value:防止误删其他线程锁
释放锁时要校验 value,推荐使用 Lua 脚本保证原子性。
十、微服务与部署面试题
77. 什么是微服务?
微服务是把一个大型系统拆分为多个独立服务,每个服务负责独立业务能力,可以独立开发、部署、扩展。
例如电商系统可拆为:
- 用户服务
- 商品服务
- 订单服务
- 支付服务
- 库存服务
78. Nacos 有什么作用?
Nacos 常用于:
- 服务注册与发现
- 配置中心
服务启动后注册到 Nacos,其他服务可以通过服务名调用它。
79. Gateway 网关有什么作用?
网关是微服务统一入口,常用于:
- 路由转发
- 登录认证
- 权限校验
- 限流
- 日志
- 跨域处理
80. Java 项目如何部署到服务器?
常见流程:
- 本地或 CI/CD 打包 jar
- 上传服务器
- 安装 JDK、MySQL、Redis、Nginx
- 启动 Spring Boot jar
- Nginx 配置反向代理
- 配置域名解析
- 配置 HTTPS
- 使用 systemd、Docker 或 Jenkins 管理服务
示例:
bash
nohup java -jar app.jar > app.log 2>&1 &
Docker 部署:
bash
docker build -t app .
docker run -d -p 8080:8080 --name app app
二十九、项目练习建议
1. 用户登录注册系统
功能:
- 用户注册
- 用户登录
- JWT 认证
- 修改密码
- 用户信息查询
- 登录拦截
技术:
text
Spring Boot + MyBatis-Plus + MySQL + JWT + Redis
2. 后台管理系统
功能:
- 登录
- 用户管理
- 角色管理
- 菜单管理
- 权限管理
- 日志管理
- 文件上传
技术:
text
Vue3 + Element Plus + Spring Boot + MyBatis-Plus + MySQL + Redis
3. 博客系统
功能:
- 文章发布
- 文章分类
- 标签管理
- 评论
- 点赞
- 后台审核
- 搜索
4. 电商系统
功能:
- 商品管理
- 购物车
- 下单
- 支付模拟
- 库存扣减
- 订单超时取消
- 秒杀
技术:
text
Spring Boot + Redis + RabbitMQ/Kafka + MySQL + Elasticsearch
5. 推荐练习顺序
text
Java 基础控制台项目
↓
MySQL 增删改查
↓
Spring Boot 用户管理接口
↓
Vue/React 调接口
↓
登录注册 + JWT
↓
后台管理系统
↓
Redis 缓存
↓
Docker 部署
↓
微服务项目
三十、总结
Java 学习不要只背语法,最好围绕项目逐步推进。
推荐主线:
text
Java 基础
↓
面向对象
↓
集合、异常、IO、泛型
↓
多线程、JVM
↓
MySQL、MyBatis
↓
Spring Boot
↓
登录认证、权限、JWT
↓
Redis、MQ、搜索
↓
Linux、Docker、Nginx 部署
↓
微服务与分布式
对于前端开发者,最实用的目标是先完成:
text
Vue3 / React + Spring Boot + MySQL + Redis 的前后端分离后台管理系统
只要你能独立完成登录、注册、权限控制、用户管理、分页查询、文件上传、接口联调、部署上线,就已经具备 Java 后端入门到初中级开发的核心能力。
附:建议学习计划
第 1 周:Java 基础
- 环境安装
- 数据类型
- 流程控制
- 数组
- 方法
- 面向对象基础
第 2 周:Java 进阶
- 集合
- 泛型
- 异常
- IO
- Lambda
- Stream
第 3 周:数据库
- MySQL
- SQL
- 表设计
- 索引
- JDBC
- MyBatis
第 4 周:Spring Boot
- Spring IOC
- Spring MVC
- REST API
- MyBatis-Plus
- 统一返回
- 全局异常
第 5 周:登录权限
- 登录注册
- JWT
- 拦截器
- 权限表设计
- Redis 缓存
第 6 周:完整项目
- 后台管理系统
- 前后端联调
- 文件上传
- 分页搜索
- 部署上线
第 7 周以后:进阶
- JVM
- 并发
- Redis 高级
- MQ
- Docker
- 微服务
- 高并发系统设计