// ===== 方法定义语法 =====
// 访问修饰符 + 返回类型 + 方法名(参数列表) { 方法体 }
public int add(int a, int b) {
return a + b;
}
public void sayHello(String name) { // void = 无返回值
System.out.println("Hello, " + name);
}
// ===== 方法重载(Overloading)—— JS 没有的特性 =====
// 同名方法,参数不同 → 编译器自动选择
public int add(int a, int b) { return a + b; }
public double add(double a, double b) { return a + b; }
public String add(String a, String b) { return a + b; }
add(1, 2); // 调用 int 版本 → 3
add(1.5, 2.5); // 调用 double 版本 → 4.0
add("Hi", "!"); // 调用 String 版本 → "Hi!"
// ===== 可变参数(varargs)—— 类似 JS 的 ...rest =====
public int sum(int... numbers) { // numbers 是 int[]
int total = 0;
for (int n : numbers) {
total += n;
}
return total;
}
sum(1, 2, 3); // 6
sum(1, 2, 3, 4, 5); // 15
🔑 static vs 实例方法 & pass-by-value
// ===== static 方法(不需要 new 对象) =====
public class MathUtils {
// 工具方法通常是 static
public static int max(int a, int b) {
return a > b ? a : b;
}
}
// 直接用类名调用
MathUtils.max(3, 5); // 5
// ===== 实例方法(需要 new 对象) =====
public class Counter {
private int count = 0; // 实例字段
public void increment() { // 实例方法
count++;
}
public int getCount() {
return count;
}
}
Counter c = new Counter(); // 必须先 new
c.increment();
c.getCount(); // 1
// ===== Java 是 pass-by-value(值传递) =====
// 原始类型:传副本(和 JS 一样)
public void change(int x) { x = 100; }
int a = 1;
change(a);
System.out.println(a); // 1(不变)
// 引用类型:传引用的副本(对象本身可被修改)
public void addItem(List<String> list) {
list.add("new"); // 会修改原始列表!
}
// 但不能让引用指向新对象:
public void replace(List<String> list) {
list = new ArrayList<>(); // 不影响外部引用
}
// 定义一个无返回值的方法
public sayHi(String name) {
System.out.println("Hi " + name);
}
// 定义可变参数方法
public int sum(int numbers) {
// numbers 当作数组使用
}
// 不需要 new 就能调用的方法
public int max(int a, int b) {
return a > b ? a : b;
}
// 泛型类定义
public class Pair<, V> {
private K key;
private V value;
}
// 接受 Number 及其子类的列表(只读)
public void print(List<? Number> list) { }
// 泛型方法定义
public static T identity(T value) {
return value;
}
🧠 小测验
Java 泛型的"类型擦除"意味着什么?
面向对象 · 01
类与对象:Java 的 class 比 JS 的 class 更"正统"
JS 的 class 是语法糖,Java 的 class 是语言核心。理解构造器、this、static 和新特性 Record。
🔄 JS vs Java 类对比
概念
JavaScript
Java
类定义
class User { }
public class User { }
构造器
constructor()
与类同名的方法
字段声明
构造器中 this.x = x
类体中声明 private int x;
this
动态绑定(容易丢失)
始终指向当前对象
静态成员
static
static(一样)
只读字段
readonly(TS)
final
数据类
手动写
record(Java 16+)
一个文件多个类
可以
一个文件只能有一个 public class
📌 类定义与构造器
// ===== 标准类定义 =====
public class User {
// 字段(必须声明类型和访问修饰符)
private String name;
private int age;
private static int userCount = 0; // 静态字段(所有实例共享)
// 构造器(方法名 = 类名,无返回类型)
public User(String name, int age) {
this.name = name; // this 引用当前对象
this.age = age;
userCount++;
}
// 构造器重载(类似默认参数的效果)
public User(String name) {
this(name, 0); // 调用另一个构造器
}
// 实例方法
public String greet() {
return "Hello, I'm %s, %d years old".formatted(name, age);
}
// 静态方法
public static int getUserCount() {
return userCount;
}
// Getter / Setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
// 使用
User alice = new User("Alice", 28);
alice.greet(); // "Hello, I'm Alice, 28 years old"
User.getUserCount(); // 1(静态方法用类名调用)
📦 Record(Java 16+)—— 数据类神器
// ===== Record —— 不可变数据类(一行搞定) =====
// 自动生成:构造器、访问器方法、equals()、hashCode()、toString()
public record UserDTO(String name, int age, String email) { }
// 使用(和普通类一样 new)
var user = new UserDTO("Alice", 28, "alice@example.com");
user.name(); // "Alice"(Record 生成的是 name() 这种访问器,不是 getName())
user.age(); // 28
System.out.println(user); // UserDTO[name=Alice, age=28, email=alice@example.com]
// Record 是不可变的
// user.name = "Bob"; ← 编译错误!没有 setter
// Record 可以有自定义方法和校验
public record Point(int x, int y) {
// 紧凑构造器(compact constructor)用于校验
public Point {
if (x < 0 || y < 0) throw new IllegalArgumentException("坐标不能为负");
}
// 自定义方法
public double distance() {
return Math.sqrt(x * x + y * y);
}
}
💡 Record vs Class:如果一个类只是用来"装数据"(DTO、值对象),优先用 Record。它自动实现了 equals/hashCode/toString,省掉大量样板代码。
📋 速查:类语法
▼
语法
说明
示例
class
普通类
public class User { }
构造器
与类同名
public User(String name) { }
this
当前对象
this.name = name;
this()
调用其他构造器
this(name, 0);
static
静态成员
static int count;
final
不可变字段
final String id;
record
不可变数据类
record Point(int x, int y) { }
new
创建对象
new User("Alice");
✏️ 填空:类与 Record
// 定义一个 Record 数据类
public ProductDTO(String name, double price) { }
// 调用其他构造器
public User(String name) {
(name, 0);
}
// Record 的访问器没有 get 前缀
var p = new ProductDTO("手机", 999.0);
String n = p.();
// 获取枚举值的名字字符串
Season s = Season.SPRING;
String name = s.(); // "SPRING"
// 带数据的枚举,字段用什么修饰?
private int code;
// 限制谁能实现接口
public interface Result
permits Success, Failure { }
// Builder 模式:链式调用最后调用
User user = new User.Builder("Alice").age(28).();
// Singleton:构造器的修饰符
DatabaseConfig() { }
// Strategy:通过什么传入不同策略?
public OrderService( strategy) { }
// ===== Controller → Service → Repository 三层架构 =====
// 类比前端:Route Handler → Business Logic → API Call
// Controller 层:接收请求,返回响应(不写业务逻辑!)
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
// 通过构造器注入 Service
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public UserDTO getUser(@PathVariable Long id) {
return userService.findById(id); // 委托给 Service
}
}
// Service 层:业务逻辑(核心!)
@Service
public class UserService {
private final UserRepository userRepo;
public UserService(UserRepository userRepo) {
this.userRepo = userRepo;
}
public UserDTO findById(Long id) {
User user = userRepo.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
return new UserDTO(user.getName(), user.getEmail());
}
}
// Repository 层:数据访问(操作数据库)
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Spring Data JPA 自动实现基础 CRUD
}
// 获取路径中的 id 参数
@GetMapping("/users/{id}")
public User get(@ Long id) { }
// 获取 JSON 请求体
@PostMapping("/users")
public User create(@ UserDTO dto) { }
// 设置路由前缀
@("/api/users")
public class UserController { }
🧠 小测验
Spring Controller 返回对象时,自动序列化为 JSON 的库是?
Spring Boot · 03
Service 与 DI:业务逻辑的家,依赖注入的核心
Service 层是写业务逻辑的地方。理解构造器注入、Bean 生命周期和 @Autowired 的区别。
🔄 注入方式对比
方式
语法
推荐度
说明
构造器注入
构造器参数
⭐⭐⭐ 强烈推荐
不可变、易测试、强制依赖
字段注入
@Autowired 字段
⭐ 不推荐
隐藏依赖、难测试
Setter 注入
@Autowired setter
⭐⭐ 偶尔用
可选依赖时使用
📌 Service 层标准写法
// ===== Service 层:业务逻辑的核心 =====
@Service // 告诉 Spring 管理这个 Bean
public class UserService {
private final UserRepository userRepo;
private final EmailService emailService;
// ✅ 构造器注入(Spring 自动注入所有参数)
// 只有一个构造器时,@Autowired 可以省略
public UserService(UserRepository userRepo, EmailService emailService) {
this.userRepo = userRepo;
this.emailService = emailService;
}
public UserDTO findById(Long id) {
User user = userRepo.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
return toDTO(user);
}
public UserDTO create(CreateUserRequest request) {
// 1. 校验
if (userRepo.existsByEmail(request.email())) {
throw new DuplicateEmailException(request.email());
}
// 2. 创建实体
var user = new User(request.name(), request.email());
// 3. 保存
User saved = userRepo.save(user);
// 4. 发通知
emailService.sendWelcome(saved.getEmail());
// 5. 返回 DTO
return toDTO(saved);
}
private UserDTO toDTO(User user) {
return new UserDTO(user.getName(), user.getEmail());
}
}
// ❌ 不推荐:字段注入
@Service
public class BadService {
@Autowired // 隐藏依赖,单测时无法轻松注入 Mock
private UserRepository repo;
}
🔄 Bean 生命周期与作用域
// ===== Bean 生命周期 =====
@Service
public class CacheService {
@PostConstruct // Bean 创建后执行(类似 componentDidMount)
public void init() {
System.out.println("缓存服务初始化...");
}
@PreDestroy // Bean 销毁前执行(类似 componentWillUnmount)
public void cleanup() {
System.out.println("清理缓存...");
}
}
// ===== @Configuration + @Bean —— 手动注册第三方库的 Bean =====
@Configuration
public class AppConfig {
@Bean // 方法返回值注册为 Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.registerModule(new JavaTimeModule());
}
}
⚠️ 常见误区:① 构造器注入的字段推荐设为 final,但不是语法强制。② Spring Bean 默认是 singleton scope(同一容器共享一个实例),不是 JVM 全局单例。③ 不要在 Service 中直接操作 HttpServletRequest/Response,那是 Controller 的事。
📋 速查:DI 相关注解
▼
注解
作用
位置
@Service
标记业务层 Bean
类
@Autowired
自动注入
构造器/字段/setter
@Bean
手动注册 Bean
@Configuration 类中的方法
@PostConstruct
初始化回调
方法
@PreDestroy
销毁回调
方法
@Qualifier
指定注入哪个 Bean
参数
@Primary
默认 Bean
类/@Bean 方法
✏️ 填空:Service 与 DI
// 构造器注入,字段用什么修饰?
private UserRepository repo;
// Bean 创建后自动执行的方法
@
public void init() { }
// 手动注册第三方库的 Bean
@
public RestTemplate restTemplate() { return new RestTemplate(); }
🧠 小测验
Spring Bean 的默认作用域是?
Spring Boot · 04
数据校验:@Valid 让你告别手动 if 判断
Spring Validation 通过注解自动校验请求参数,比手动写 if-else 优雅得多。类似前端的 Zod/Yup 但更声明式。
// 全局异常处理器注解
@
public class GlobalHandler { }
// 处理特定类型的异常
@(UserNotFoundException.class)
public ErrorResponse handle(UserNotFoundException ex) { }
// 自定义异常继承
public class MyException extends { }
🧠 小测验
@RestControllerAdvice 的作用范围是?
Spring Boot · 06
连接 MySQL:Spring Data JPA 让 CRUD 自动化
Spring Data JPA 能自动生成 SQL,你只需定义接口方法名。类似前端的 Prisma ORM。