当前位置: 首页 > news >正文

Java 类类型

Note: This article has been written with the assistance of AI.

普通类 (Regular Class)

类的定义和基本结构

类的定义语法

[访问修饰符] class 类名 [extends 父类] [implements 接口1, 接口2, ...] {// 成员变量// 构造方法// 成员方法// 代码块// 内部类
}

基本示例

public class Person {// 成员变量private String name;private int age;// 构造方法public Person() {// 默认构造方法}public Person(String name, int age) {this.name = name;this.age = age;}// 成员方法public void introduce() {System.out.println("我叫" + name + ",今年" + age + "岁");}// getter和setter方法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) {this.age = age;}}
}

访问修饰符

类级别的访问修饰符

// public类:在任何地方都可以访问
public class PublicClass {// ...
}// 默认修饰符类:只能在同一个包内访问
class DefaultClass {// ...
}// 注意:一个Java文件中只能有一个public类

成员级别的访问修饰符

public class AccessExample {public String publicVar = "公共变量";      // 任何地方都可以访问protected String protectedVar = "受保护变量"; // 同包或子类可以访问String defaultVar = "默认变量";           // 同包可以访问private String privateVar = "私有变量";    // 只能在本类中访问// 方法同样适用这些修饰符public void publicMethod() {}protected void protectedMethod() {}void defaultMethod() {}private void privateMethod() {}
}

成员变量

变量类型

public class VariableTypes {// 实例变量 - 每个对象都有自己的副本private String instanceVar;// 类变量(静态变量) - 所有对象共享private static int classVar;// 常量public static final double PI = 3.14159;// 易变变量(多线程环境下使用)private volatile boolean flag;// 瞬态变量(不被序列化)private transient String tempData;
}

实例变量 (Instance Variables)

  • 属于对象的实例,每个对象都有自己独立的副本
  • 生命周期与对象相同,随对象创建而创建,随对象销毁而销毁
  • 用于存储对象的状态信息
public class Student {// 实例变量private String name;private int age;public Student(String name, int age) {this.name = name;  // 使用this区分实例变量和参数this.age = age;}public void displayInfo() {System.out.println("Name: " + name + ", Age: " + age);}public static void main(String[] args) {Student student1 = new Student("Alice", 20);Student student2 = new Student("Bob", 22);student1.displayInfo();  // 输出: Name: Alice, Age: 20student2.displayInfo();  // 输出: Name: Bob, Age: 22// 每个对象有独立的实例变量副本System.out.println(student1.name);  // AliceSystem.out.println(student2.name);  // Bob (不同的值)}
}

类变量/静态变量 (Class/Static Variables)

  • 属于类本身,所有对象共享同一个副本
  • 在类加载时初始化,程序结束时销毁
  • 用于存储类级别的共享数据
public class Employee {// 实例变量private String name;// 类变量 - 所有员工共享private static int employeeCount = 0;private static String companyName = "Tech Corp";public Employee(String name) {this.name = name;employeeCount++;  // 每次创建对象时递增共享计数器}public static void displayCompanyInfo() {System.out.println("Company: " + companyName);System.out.println("Total Employees: " + employeeCount);// System.out.println(name);  // 错误!静态方法不能访问实例变量}public static void setCompanyName(String newName) {companyName = newName;  // 修改影响所有对象}public static void main(String[] args) {Employee emp1 = new Employee("John");Employee emp2 = new Employee("Jane");Employee.displayCompanyInfo();// 输出:// Company: Tech Corp// Total Employees: 2Employee.setCompanyName("New Tech Corp");Employee.displayCompanyInfo();// 输出:// Company: New Tech Corp  // Total Employees: 2}
}

常量 (Constants)

  • 使用 final 关键字声明,值一旦设定就不能修改
  • 通常与 static 结合使用,作为类级别的常量
  • 命名约定:全大写,单词间用下划线分隔
public class MathConstants {// 常量public static final double PI = 3.141592653589793;public static final double E = 2.718281828459045;public static final int MAX_RETRY_COUNT = 3;// 实例常量 - 每个对象有自己的副本,但创建后不能修改private final long creationTime;public MathConstants() {this.creationTime = System.currentTimeMillis();  // 只能在构造函数中赋值}public double calculateCircleArea(double radius) {return PI * radius * radius;  // 使用常量}public static void main(String[] args) {System.out.println("PI: " + MathConstants.PI);System.out.println("E: " + MathConstants.E);MathConstants math = new MathConstants();double area = math.calculateCircleArea(5.0);System.out.println("Area: " + area);// MathConstants.PI = 3.14;  // 编译错误!常量不能修改}
}

易变变量 (Volatile Variables)

  • 确保多线程环境下变量的可见性
  • 防止指令重排序优化
  • 不保证原子性,适合作为状态标志
public class VolatileExample {// 易变变量 - 确保多线程可见性private volatile boolean running = true;private volatile int counter = 0;public void startWorker() {Thread worker = new Thread(() -> {while (running) {  // 其他线程修改running时立即可见counter++;try {System.out.println(running + " Counter: " + counter);Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}System.out.println(running + " Worker stopped. Counter: " + counter);});worker.start();}public void stopWorker() {running = false;  // 主线程修改,工作线程立即可见}public static void main(String[] args) throws InterruptedException {VolatileExample example = new VolatileExample();example.startWorker();Thread.sleep(1000);  // 让工作线程运行1秒example.stopWorker();Thread.sleep(100);  // 给工作线程时间结束}
}
可见性保证
  • 问题:在多核CPU架构下,每个线程可能有自己的缓存,对变量的修改可能不会立即对其他线程可见
  • 解决volatile确保当一个线程修改变量时,新值立即被写回主内存,其他线程读取时直接从主内存获取最新值
防止指令重排序
  • 问题:JVM和处理器会对指令进行重排序优化,可能破坏程序的预期执行顺序
  • 解决volatile建立"happens-before"关系,确保在volatile写操作之前的所有操作都对后续的读操作可见
不保证原子性
  • 限制volatile不保证复合操作的原子性(如i++)
  • 适用场景:适合作为简单的状态标志,不适合需要原子性的计数器等场景
详细示例代码
示例1:可见性问题的演示和解决
public class VisibilityExample {// 不使用 volatile - 可能出现可见性问题private static boolean stopRequested = false;// 使用 volatile - 确保可见性private static volatile boolean volatileStopRequested = false;public static void main(String[] args) throws InterruptedException {demonstrateVisibilityProblem();Thread.sleep(1000);demonstrateVolatileSolution();}// 演示可见性问题public static void demonstrateVisibilityProblem() throws InterruptedException {stopRequested = false;Thread worker = new Thread(() -> {int count = 0;while (!stopRequested) {count++;// 一些处理工作}System.out.println("普通变量 - 工作线程结束,循环次数: " + count);});worker.start();Thread.sleep(100); // 确保工作线程开始运行stopRequested = true; // 主线程修改标志System.out.println("普通变量 - 主线程设置了停止标志");worker.join(1000); // 等待工作线程结束,最多1秒if (worker.isAlive()) {System.out.println("普通变量 - 工作线程未停止!存在可见性问题");worker.interrupt();}}// 演示volatile解决方案public static void demonstrateVolatileSolution() throws InterruptedException {volatileStopRequested = false;Thread worker = new Thread(() -> {int count = 0;while (!volatileStopRequested) {count++;// 一些处理工作}System.out.println("Volatile变量 - 工作线程结束,循环次数: " + count);});worker.start();Thread.sleep(100); // 确保工作线程开始运行volatileStopRequested = true; // 主线程修改标志System.out.println("Volatile变量 - 主线程设置了停止标志");worker.join(1000);if (!worker.isAlive()) {System.out.println("Volatile变量 - 工作线程成功停止");}}
}
示例2:指令重排序的防止

正常情况下(无重排序):

  • 线程1执行:a = 1x = b
  • 线程2执行:b = 1y = a

可能的执行结果:

  • x=0, y=1(线程1先执行完)
  • x=1, y=0(线程2先执行完)
  • x=1, y=1(两个线程交错执行)

理论上不可能出现 x=0, y=0

由于编译器和处理器的优化,实际执行顺序可能变成:

// 线程1可能重排序为:
x = b;  // 先读b
a = 1;  // 后写a// 线程2可能重排序为:
y = a;  // 先读a  
b = 1;  // 后写b

这样就会出现:

  1. 线程1先执行 x = b(此时b=0,所以x=0)
  2. 线程2先执行 y = a(此时a=0,所以y=0)
  3. 然后两个线程分别执行赋值操作

结果x=0, y=0,违反了程序逻辑预期!

package VolatileVariables;public class InstructionReorderingExample {private static int x = 0, y = 0;private static int a = 0, b = 0;// 使用volatile防止重排序private static volatile boolean ready = false;private static volatile int result = 0;public static void main(String[] args) throws InterruptedException {// 演示指令重排序问题demonstrateReordering();Thread.sleep(1000);// 演示volatile解决方案demonstrateVolatilePrevention();}// 演示指令重排序问题public static void demonstrateReordering() throws InterruptedException {int count = 0;for (int i = 0; i < 100000; i++) {x = y = a = b = 0;Thread one = new Thread(() -> {a = 1;x = b;});Thread two = new Thread(() -> {b = 1;y = a;});one.start();two.start();one.join();two.join();// 如果指令没有重排序,x和y不可能同时为0if (x == 0 && y == 0) {count++;System.out.println("检测到指令重排序! 次数: " + count);} else {System.out.println("指令没有重排序!");}   }}// 演示volatile防止重排序public static void demonstrateVolatilePrevention() {Thread writer = new Thread(() -> {// 这些操作在ready赋值之前完成,且对reader线程可见result = 42;ready = true; // volatile写,建立happens-before关系});Thread reader = new Thread(() -> {if (ready) { // volatile读,看到writer线程的所有写操作System.out.println("结果: " + result); // 保证看到42,而不是0}});writer.start();reader.start();}
}
示例3:原子性限制的演示
public class AtomicityExample {// volatile不保证原子性private static volatile int volatileCounter = 0;// 使用AtomicInteger保证原子性private static java.util.concurrent.atomic.AtomicInteger atomicCounter = new java.util.concurrent.atomic.AtomicInteger(0);// 使用synchronized保证原子性private static int synchronizedCounter = 0;public static void main(String[] args) throws InterruptedException {demonstrateVolatileAtomicityProblem();Thread.sleep(1000);demonstrateAtomicSolution();Thread.sleep(1000);demonstrateSynchronizedSolution();}// 演示volatile的原子性问题public static void demonstrateVolatileAtomicityProblem() throws InterruptedException {volatileCounter = 0;Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < 1000; j++) {volatileCounter++; // 这不是原子操作!}});}for (Thread t : threads) t.start();for (Thread t : threads) t.join();System.out.println("Volatile计数器期望值: 10000, 实际值: " + volatileCounter);}// 演示AtomicInteger解决方案public static void demonstrateAtomicSolution() throws InterruptedException {atomicCounter.set(0);Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < 1000; j++) {atomicCounter.incrementAndGet(); // 原子操作}});}for (Thread t : threads) t.start();for (Thread t : threads) t.join();System.out.println("Atomic计数器期望值: 10000, 实际值: " + atomicCounter.get());}// 演示synchronized解决方案public static void demonstrateSynchronizedSolution() throws InterruptedException {synchronizedCounter = 0;Thread[] threads = new Thread[10];for (int i = 0; i < 10; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < 1000; j++) {incrementSynchronized(); // 同步方法}});}for (Thread t : threads) t.start();for (Thread t : threads) t.join();System.out.println("Synchronized计数器期望值: 10000, 实际值: " + synchronizedCounter);}private static synchronized void incrementSynchronized() {synchronizedCounter++;}
}
示例4:正确的volatile使用场景 - 状态标志
public class CorrectVolatileUsage {// 正确的volatile使用 - 状态标志private volatile boolean shutdownRequested = false;// 配置信息 - 适合使用volatile(发布-读取模式)private volatile Configuration config = new Configuration("default", 1000);private static class Configuration {private final String name;private final int timeout;public Configuration(String name, int timeout) {this.name = name;this.timeout = timeout;}@Overridepublic String toString() {return "Configuration{name='" + name + "', timeout=" + timeout + "}";}}public void startServer() {Thread serverThread = new Thread(() -> {while (!shutdownRequested) {try {// 模拟服务器工作processRequest();// 读取当前配置(volatile保证看到最新值)Configuration currentConfig = config;System.out.println("使用配置: " + currentConfig);} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}System.out.println("服务器正常关闭");});serverThread.start();}public void requestShutdown() {shutdownRequested = true; // volatile写,服务器线程立即可见System.out.println("关闭请求已发送");}public void updateConfiguration(Configuration newConfig) {config = newConfig; // volatile写,新配置立即可见System.out.println("配置已更新: " + newConfig);}private void processRequest() throws InterruptedException {Thread.sleep(500); // 模拟请求处理}public static void main(String[] args) throws InterruptedException {CorrectVolatileUsage server = new CorrectVolatileUsage();server.startServer();// 运行一段时间后更新配置Thread.sleep(2000);server.updateConfiguration(new Configuration("production", 2000));// 再运行一段时间后关闭Thread.sleep(2000);server.requestShutdown();}
}
示例5:双重检查锁定模式
public class DoubleCheckedLocking {// 使用volatile的单例模式private static volatile DoubleCheckedLocking instance;private final String data;private DoubleCheckedLocking() {// 模拟耗时的初始化try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}this.data = "初始化数据";}// 正确的双重检查锁定public static DoubleCheckedLocking getInstance() {if (instance == null) { // 第一次检查(不加锁)synchronized (DoubleCheckedLocking.class) {if (instance == null) { // 第二次检查(加锁)instance = new DoubleCheckedLocking(); // volatile写}}}return instance;}// 错误的实现(不使用volatile)private static DoubleCheckedLocking brokenInstance;public static DoubleCheckedLocking getBrokenInstance() {if (brokenInstance == null) {synchronized (DoubleCheckedLocking.class) {if (brokenInstance == null) {brokenInstance = new DoubleCheckedLocking(); // 可能发生重排序}}}return brokenInstance;}public String getData() {return data;}public static void main(String[] args) {// 测试正确的实现Thread t1 = new Thread(() -> {DoubleCheckedLocking instance = DoubleCheckedLocking.getInstance();System.out.println("线程1获取实例: " + instance.getData());});Thread t2 = new Thread(() -> {DoubleCheckedLocking instance = DoubleCheckedLocking.getInstance();System.out.println("线程2获取实例: " + instance.getData());});t1.start();t2.start();}
}
总结:使用volatile的场景
  1. 状态标志 - 简单的boolean标志,用于控制线程执行
  2. 一次性安全发布 - 确保对象构造完成后才对其他线程可见
  3. 独立观察 - 定期"发布"观察结果供程序使用
  4. 双重检查锁定 - 与synchronized配合实现延迟初始化
总结:不使用volatile的场景
  1. 复合操作 - i++、check-then-act等需要原子性的操作
  2. 多个相关变量 - 需要同时更新多个相关变量时
  3. 频繁写入 - 写入频繁且需要原子性时,考虑使用锁
总结:volatile vs synchronized
特性 volatile synchronized
可见性 ✅ 保证 ✅ 保证
原子性 ❌ 不保证 ✅ 保证
互斥性 ❌ 不提供 ✅ 提供
性能 较高 较低
适用场景 状态标志、一次性发布 复合操作、临界区

瞬态变量 (Transient Variables)

  • 标记变量不被序列化
  • 用于存储临时数据或敏感信息
  • 反序列化时被设为默认值
import java.io.*;class User implements Serializable {// 会被序列化private String username;private String email;// 不会被序列化private transient String password;private transient Thread currentThread;  // Thread不可序列化// 缓存数据,不需要序列化private transient String cachedDisplayName;public User(String username, String email, String password) {this.username = username;this.email = email;this.password = password;this.currentThread = Thread.currentThread();updateCachedDisplayName();}private void updateCachedDisplayName() {this.cachedDisplayName = username + " <" + email + ">";}public void displayInfo() {System.out.println("Username: " + username);System.out.println("Email: " + email);System.out.println("Password: " + (password != null ? "***" : "null"));System.out.println("Thread: " + (currentThread != null ? currentThread.getName() : "null"));System.out.println("Cached: " + cachedDisplayName);}// 反序列化后的回调方法private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {ois.defaultReadObject();// 重新计算瞬态变量updateCachedDisplayName();currentThread = Thread.currentThread();}
}public class TransientExample {public static void main(String[] args) {User user = new User("john_doe", "john@example.com", "secret123");System.out.println("=== 原始对象 ===");user.displayInfo();// 序列化try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.ser"))) {oos.writeObject(user);} catch (IOException e) {e.printStackTrace();}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.ser"))) {User deserializedUser = (User) ois.readObject();System.out.println("\n=== 反序列化后的对象 ===");deserializedUser.displayInfo();  // password为null,cachedDisplayName被重新计算} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
阻止序列化
  • 作用:标记的变量在对象序列化时会被跳过,不写入字节流
  • 效果:减少序列化数据大小,保护敏感信息
默认值恢复
  • 反序列化:被标记为transient的变量在反序列化时会被设为默认值
  • 默认值:对象为null,数值类型为0,boolean为false
适用场景
  • 临时计算数据、缓存结果
  • 敏感信息(密码、密钥等)
  • 不可序列化的对象引用
  • 运行时状态信息
详细示例代码
示例1:基础使用和序列化效果演示
import java.io.*;
import java.util.Date;class User implements Serializable {// 会被序列化的字段private String username;private String email;private Date registrationDate;// 不会被序列化的字段private transient String password;private transient int loginCount;  // 临时统计信息private transient String sessionId; // 会话IDpublic User(String username, String email, String password) {this.username = username;this.email = email;this.password = password;this.registrationDate = new Date();this.loginCount = 0;generateSessionId();}public void login() {loginCount++;generateSessionId();System.out.println(username + " 登录成功,登录次数: " + loginCount);}private void generateSessionId() {this.sessionId = "SESSION_" + System.currentTimeMillis() + "_" + username;}public void displayUserInfo() {System.out.println("=== 用户信息 ===");System.out.println("用户名: " + username);System.out.println("邮箱: " + email);System.out.println("密码: " + (password != null ? "***" : "null"));System.out.println("注册时间: " + registrationDate);System.out.println("登录次数: " + loginCount);System.out.println("会话ID: " + sessionId);System.out.println();}
}public class BasicTransientExample {public static void main(String[] args) {// 创建用户对象User user = new User("alice", "alice@example.com", "secret123");user.login();user.login(); // 模拟两次登录System.out.println("=== 原始对象 ===");user.displayUserInfo();// 序列化到文件String filename = "user.dat";try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {oos.writeObject(user);System.out.println("对象序列化完成");} catch (IOException e) {e.printStackTrace();}// 从文件反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {User deserializedUser = (User) ois.readObject();System.out.println("=== 反序列化后的对象 ===");deserializedUser.displayUserInfo();// 注意:password为null,loginCount为0,sessionId为null} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
示例2:敏感信息保护
import java.io.*;
import java.util.Arrays;class BankAccount implements Serializable {private String accountNumber;private String accountHolder;private double balance;// 敏感信息 - 不序列化private transient char[] password;private transient String securityQuestion;private transient String securityAnswer;// 临时数据 - 不序列化private transient String lastTransactionId;private transient boolean isLoggedIn;public BankAccount(String accountNumber, String accountHolder, double balance, char[] password, String securityQuestion, String securityAnswer) {this.accountNumber = accountNumber;this.accountHolder = accountHolder;this.balance = balance;this.password = password;this.securityQuestion = securityQuestion;this.securityAnswer = securityAnswer;this.isLoggedIn = false;}public boolean login(char[] inputPassword) {if (Arrays.equals(password, inputPassword)) {isLoggedIn = true;generateTransactionId();return true;}return false;}public void deposit(double amount) {if (isLoggedIn && amount > 0) {balance += amount;generateTransactionId();System.out.println("存款成功: " + amount);}}private void generateTransactionId() {this.lastTransactionId = "TXN_" + System.currentTimeMillis();}// 自定义序列化逻辑private void writeObject(ObjectOutputStream oos) throws IOException {oos.defaultWriteObject(); // 序列化非transient字段// 不写入password等敏感信息System.out.println("序列化完成 - 敏感信息已被排除");}// 自定义反序列化逻辑private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {ois.defaultReadObject(); // 反序列化非transient字段// transient字段保持为默认值this.password = null;this.securityQuestion = null;this.securityAnswer = null;this.isLoggedIn = false;System.out.println("反序列化完成 - 需要重新登录");}// 清理敏感信息public void clearSensitiveData() {if (password != null) {Arrays.fill(password, '0'); // 覆盖密码数据password = null;}securityQuestion = null;securityAnswer = null;}public void displayAccountInfo() {System.out.println("=== 账户信息 ===");System.out.println("账户号: " + accountNumber);System.out.println("持有人: " + accountHolder);System.out.println("余额: " + balance);System.out.println("密码: " + (password != null ? "***" : "null"));System.out.println("安全提示: " + securityQuestion);System.out.println("登录状态: " + isLoggedIn);System.out.println("最后交易ID: " + lastTransactionId);System.out.println();}@Overrideprotected void finalize() throws Throwable {clearSensitiveData(); // 确保敏感数据被清理super.finalize();}
}public class SensitiveDataExample {public static void main(String[] args) {// 创建银行账户char[] password = "securePass123".toCharArray();BankAccount account = new BankAccount("123456789", "张三", 5000.0, password,"你出生的城市?","北京");// 登录并执行操作account.login(password);account.deposit(1000);System.out.println("=== 原始账户对象 ===");account.displayAccountInfo();// 序列化String filename = "account.dat";try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {oos.writeObject(account);} catch (IOException e) {e.printStackTrace();}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {BankAccount restoredAccount = (BankAccount) ois.readObject();System.out.println("=== 恢复的账户对象 ===");restoredAccount.displayAccountInfo();// 需要重新登录char[] newPassword = "securePass123".toCharArray();boolean loginSuccess = restoredAccount.login(newPassword);System.out.println("重新登录结果: " + loginSuccess);Arrays.fill(newPassword, '0'); // 清理密码数组} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}// 清理原始对象的敏感数据account.clearSensitiveData();}
}
示例3:不可序列化对象处理
import java.io.*;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.concurrent.ThreadPoolExecutor;class NetworkService implements Serializable {private String serviceName;private String host;private int port;// 不可序列化的对象必须标记为transientprivate transient Socket connection;private transient ThreadPoolExecutor executor;private transient Runtime runtime;// 临时状态信息private transient LocalDateTime lastConnected;private transient boolean isConnected;// 用于重建的配置信息private long connectionTimeout;private int maxThreads;public NetworkService(String serviceName, String host, int port) {this.serviceName = serviceName;this.host = host;this.port = port;this.connectionTimeout = 5000L;this.maxThreads = 10;initializeTransientFields();}private void initializeTransientFields() {this.runtime = Runtime.getRuntime();this.lastConnected = LocalDateTime.now();this.isConnected = false;System.out.println("初始化瞬态字段完成");}public void connect() {try {// 模拟网络连接System.out.println("连接到 " + host + ":" + port);this.isConnected = true;this.lastConnected = LocalDateTime.now();} catch (Exception e) {System.out.println("连接失败: " + e.getMessage());}}// 自定义序列化方法private void writeObject(ObjectOutputStream oos) throws IOException {oos.defaultWriteObject(); // 序列化非transient字段// 不保存连接状态System.out.println("序列化: 保存服务配置,跳过网络连接状态");}// 自定义反序列化方法private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {ois.defaultReadObject(); // 反序列化非transient字段// 重新初始化transient字段initializeTransientFields();System.out.println("反序列化: 重新初始化瞬态字段");}public void displayServiceInfo() {System.out.println("=== 服务信息 ===");System.out.println("服务名称: " + serviceName);System.out.println("主机: " + host);System.out.println("端口: " + port);System.out.println("连接状态: " + isConnected);System.out.println("最后连接: " + lastConnected);System.out.println("Socket: " + (connection != null ? "已初始化" : "null"));System.out.println("Executor: " + (executor != null ? "已初始化" : "null"));System.out.println("Runtime: " + (runtime != null ? "可用" : "null"));System.out.println();}// 重新连接方法public void reconnect() {System.out.println("重新建立连接...");connect();}
}public class NonSerializableExample {public static void main(String[] args) {// 创建网络服务NetworkService service = new NetworkService("DataService", "api.example.com", 8080);service.connect();System.out.println("=== 原始服务对象 ===");service.displayServiceInfo();// 序列化String filename = "service.dat";try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {oos.writeObject(service);} catch (IOException e) {e.printStackTrace();}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {NetworkService restoredService = (NetworkService) ois.readObject();System.out.println("=== 恢复的服务对象 ===");restoredService.displayServiceInfo();// 需要重新连接restoredService.reconnect();restoredService.displayServiceInfo();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
示例4:缓存数据和计算结果的transient使用
import java.io.*;
import java.util.ArrayList;
import java.util.List;class DataProcessor implements Serializable {private String dataSource;private List<Integer> rawData;// 缓存的计算结果 - 不需要序列化private transient Integer cachedSum;private transient Double cachedAverage;private transient List<Integer> cachedSortedData;// 计算状态private transient boolean isCalculated;private transient long calculationTime;public DataProcessor(String dataSource) {this.dataSource = dataSource;this.rawData = new ArrayList<>();this.isCalculated = false;}public void addData(int value) {rawData.add(value);invalidateCache(); // 数据变化时使缓存失效}private void invalidateCache() {cachedSum = null;cachedAverage = null;cachedSortedData = null;isCalculated = false;}public void calculate() {if (!isCalculated) {long startTime = System.currentTimeMillis();// 计算总和cachedSum = rawData.stream().mapToInt(Integer::intValue).sum();// 计算平均值cachedAverage = rawData.isEmpty() ? 0.0 : rawData.stream().mapToInt(Integer::intValue).average().orElse(0.0);// 排序数据cachedSortedData = new ArrayList<>(rawData);cachedSortedData.sort(Integer::compareTo);calculationTime = System.currentTimeMillis() - startTime;isCalculated = true;System.out.println("计算完成,耗时: " + calculationTime + "ms");}}public void displayResults() {System.out.println("=== 数据处理结果 ===");System.out.println("数据源: " + dataSource);System.out.println("原始数据: " + rawData);System.out.println("数据总和: " + (cachedSum != null ? cachedSum : "未计算"));System.out.println("平均值: " + (cachedAverage != null ? cachedAverage : "未计算"));System.out.println("排序数据: " + (cachedSortedData != null ? cachedSortedData : "未计算"));System.out.println("计算状态: " + isCalculated);System.out.println();}// 自定义序列化private void writeObject(ObjectOutputStream oos) throws IOException {oos.defaultWriteObject(); // 只保存原始数据System.out.println("序列化: 保存原始数据,跳过缓存结果");}// 自定义反序列化private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {ois.defaultReadObject();// 重新初始化transient字段this.isCalculated = false;this.cachedSum = null;this.cachedAverage = null;this.cachedSortedData = null;System.out.println("反序列化: 重新初始化缓存字段");}// 重新计算方法public void recalculate() {System.out.println("重新计算数据...");calculate();}
}public class CacheDataExample {public static void main(String[] args) {// 创建数据处理器DataProcessor processor = new DataProcessor("sensor_data");// 添加数据processor.addData(10);processor.addData(25);processor.addData(5);processor.addData(30);processor.addData(15);// 计算并显示结果processor.calculate();System.out.println("=== 原始对象(计算后) ===");processor.displayResults();// 序列化String filename = "processor.dat";try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {oos.writeObject(processor);} catch (IOException e) {e.printStackTrace();}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {DataProcessor restoredProcessor = (DataProcessor) ois.readObject();System.out.println("=== 恢复的对象 ===");restoredProcessor.displayResults(); // 缓存数据丢失// 重新计算restoredProcessor.recalculate();restoredProcessor.displayResults();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
总结:transient 关键字的主要用途
  1. 安全保护

    • 防止敏感信息(密码、密钥等)被持久化
    • 避免安全漏洞
  2. 资源优化

    • 减少序列化数据大小
    • 避免序列化大型临时数据
  3. 运行时状态管理

    • 不保存临时状态信息
    • 重新创建对象时初始化新状态
  4. 不可序列化对象处理

    • 处理Socket、Thread等不可序列化的对象引用
    • 在反序列化时重新创建这些资源

最佳实践:

  • writeObject/readObject方法中自定义序列化逻辑
  • 及时清理敏感数据的内存
  • 为transient字段提供重新初始化的方法
  • 考虑使用@Transient注解(JPA)与transient关键字的区别

变量的访问规则

静态方法不能直接访问实例变量,但实例方法可以访问静态变量。

静态方法不能直接访问实例变量
public class VariableExample {// 实例变量private String instanceVar = "实例变量";// 静态变量private static String staticVar = "静态变量";// 静态方法public static void staticMethod() {// ❌ 编译错误:不能直接访问实例变量System.out.println(instanceVar);// ✅ 正确:可以访问静态变量System.out.println(staticVar);// ✅ 正确:通过对象实例访问实例变量VariableExample obj = new VariableExample();System.out.println(obj.instanceVar);}
}
实例方法可以访问所有变量
public class VariableExample {// 实例变量private String instanceVar = "实例变量";// 静态变量private static String staticVar = "静态变量";// 实例方法public void instanceMethod() {// ✅ 正确:访问自己的实例变量System.out.println(instanceVar);// ✅ 正确:访问静态变量System.out.println(staticVar);// ✅ 正确:访问其他对象的实例变量VariableExample other = new VariableExample();System.out.println(other.instanceVar);}
}
示例
public class VariableAccessDemo {// 实例变量private int instanceCount = 10;// 静态变量  private static int staticCount = 20;// 静态方法public static void staticMethod() {// System.out.println(instanceCount); // ❌ 编译错误System.out.println("静态方法访问静态变量: " + staticCount); // ✅// 通过创建对象访问实例变量VariableAccessDemo obj = new VariableAccessDemo();System.out.println("通过对象访问实例变量: " + obj.instanceCount); // ✅}// 实例方法public void instanceMethod() {System.out.println("实例方法访问实例变量: " + instanceCount); // ✅System.out.println("实例方法访问静态变量: " + staticCount); // ✅// 修改静态变量staticCount++;System.out.println("修改后静态变量: " + staticCount);}public static void main(String[] args) {// 静态方法调用staticMethod();// 实例方法调用VariableAccessDemo demo = new VariableAccessDemo();demo.instanceMethod();}
}
访问规则总结
方法/变量类型 实例变量 静态变量
静态方法 ❌ 不能直接访问
✅ 可通过对象访问
✅ 可以直接访问
实例方法 ✅ 可以直接访问 ✅ 可以直接访问
根本原因

生命周期不同

  • 静态变量:类加载时初始化,程序结束时销毁
  • 实例变量:对象创建时初始化,对象销毁时回收
  • 静态方法:不需要对象实例即可调用
  • 实例方法:必须通过对象实例调用

因此

  • 静态方法调用时,可能还没有实例变量存在
  • 实例方法调用时,静态变量肯定已经存在

变量初始化

public class VariableInitialization {// 直接初始化private String name = "默认名称";private int age = 0;// 静态变量初始化private static int count = 0;// 使用代码块初始化private List<String> list;{// 实例初始化块list = new ArrayList<>();list.add("item1");list.add("item2");}static {// 静态初始化块count = 100;}
}

构造方法

构造方法类型

public class ConstructorExample {private String name;private int age;private String address;// 默认构造方法public ConstructorExample() {this.name = "未知";this.age = 0;this.address = "未知地址";}// 带参数构造方法public ConstructorExample(String name, int age) {this.name = name;this.age = age;this.address = "未知地址";}// 构造方法重载public ConstructorExample(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}// 拷贝构造方法public ConstructorExample(ConstructorExample other) {this.name = other.name;this.age = other.age;this.address = other.address;}// 构造方法调用其他构造方法(必须第一行)public ConstructorExample(String name) {this(name, 0, "未知地址");}
}

成员方法

方法定义

public class MethodExample {// 无返回值方法public void printInfo() {System.out.println("这是一个无返回值方法");}// 有返回值方法public int calculateSum(int a, int b) {return a + b;}// 静态方法public static void staticMethod() {System.out.println("这是一个静态方法");}// final方法(不能被子类重写)public final void finalMethod() {System.out.println("这是一个final方法");}// 可变参数方法public void varArgsMethod(String... strings) {for (String str : strings) {System.out.println(str);}}
}

实例方法可以访问静态方法,但静态方法不能直接访问实例方法。

静态方法不能直接访问实例方法

public class Example {private String instanceVariable = "实例变量";// 实例方法public void instanceMethod() {System.out.println("实例方法");}// 静态方法public static void staticMethod() {// 编译错误!不能直接访问实例方法instanceMethod(); // ❌ 错误// 编译错误!不能直接访问实例变量System.out.println(instanceVariable); // ❌ 错误}
}

原因:静态方法属于类级别,在类加载时就可以调用,此时可能还没有创建任何对象实例。

实例方法可以访问静态方法

public class Example {private static String staticVariable = "静态变量";// 静态方法public static void staticMethod() {System.out.println("静态方法");}// 实例方法public void instanceMethod() {// ✅ 可以访问静态方法staticMethod();// ✅ 可以访问静态变量System.out.println(staticVariable);// ✅ 也可以访问自己的实例成员System.out.println("实例方法访问静态成员");}
}

原因:实例方法调用时,对象已经存在,静态成员也肯定已经初始化。

特殊情况:通过对象引用访问

public class Example {public void instanceMethod() {System.out.println("实例方法");}public static void staticMethod() {// 可以通过创建实例来访问实例方法Example obj = new Example();obj.instanceMethod(); // ✅ 正确}
}

总结表格

方法类型 能否访问实例方法 能否访问静态方法 能否访问实例变量 能否访问静态变量
静态方法 ❌ 不能直接访问 ✅ 可以访问 ❌ 不能直接访问 ✅ 可以访问
实例方法 ✅ 可以访问 ✅ 可以访问 ✅ 可以访问 ✅ 可以访问

记忆技巧

  • 静态的不能碰非静态的(直接访问)
  • 非静态的可以碰所有的
  • 静态成员属于类,实例成员属于对象

方法重载

public class MethodOverloading {// 方法重载:方法名相同,参数列表不同public void display() {System.out.println("无参数显示");}public void display(String message) {System.out.println("显示消息: " + message);}public void display(String message, int times) {for (int i = 0; i < times; i++) {System.out.println(message);}}public void display(int number) {System.out.println("显示数字: " + number);}
}

代码块

实例初始化块

public class InstanceBlockExample {private int x;private int y;// 实例初始化块 - 每次创建对象时执行{System.out.println("实例初始化块执行");x = 10;y = 20;}public InstanceBlockExample() {System.out.println("构造方法执行");}
}

静态初始化块

public class StaticBlockExample {private static int count;private static List<String> names;// 静态初始化块 - 类加载时执行一次static {System.out.println("静态初始化块执行");count = 0;names = new ArrayList<>();names.add("张三");names.add("李四");}
}

this & super 关键字

this关键字

this关键字代表当前对象的引用,指向调用该方法的对象实例。

区分成员变量和局部变量

public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;  // this.name指成员变量,name指参数this.age = age;    // this.age指成员变量,age指参数}public void setName(String name) {this.name = name;}
}

调用当前类的其他构造方法

public class Rectangle {private int width;private int height;private String color;// 无参构造public Rectangle() {this(10, 20);  // 调用有参构造}// 有参构造public Rectangle(int width, int height) {this(width, height, "red");  // 调用三参构造}// 三参构造public Rectangle(int width, int height, String color) {this.width = width;this.height = height;this.color = color;}
}

作为方法参数传递当前对象

public class Calculator {private int value;public Calculator(int value) {this.value = value;}public void display() {Printer.print(this);  // 将当前对象传递给其他方法}
}class Printer {public static void print(Calculator calc) {System.out.println("Value: " + calc.value);}
}

返回当前对象(实现方法链)

public class StringBuilderExample {private StringBuilder sb = new StringBuilder();public StringBuilderExample append(String text) {sb.append(text);return this;  // 返回当前对象,支持链式调用}public StringBuilderExample appendLine(String text) {sb.append(text).append("\n");return this;}// 使用示例public static void main(String[] args) {StringBuilderExample example = new StringBuilderExample();example.append("Hello").appendLine(" World").append("Java");// 链式调用}
}

super关键字

super关键字代表父类对象的引用,用于访问父类的成员变量、方法和构造方法。

调用父类构造方法

class Animal {private String name;private int age;public Animal(String name, int age) {this.name = name;this.age = age;}
}class Dog extends Animal {private String breed;public Dog(String name, int age, String breed) {super(name, age);  // 必须放在第一行,调用父类构造方法this.breed = breed;}
}

访问父类的成员变量

class Parent {protected String message = "Parent message";
}class Child extends Parent {private String message = "Child message";public void display() {System.out.println("Child: " + this.message);      // 输出:Child messageSystem.out.println("Parent: " + super.message);    // 输出:Parent message}
}

调用父类的方法

class Vehicle {public void start() {System.out.println("Vehicle starting...");}
}class Car extends Vehicle {@Overridepublic void start() {super.start();  // 调用父类的start方法System.out.println("Car starting with ignition...");}public void test() {super.start();  // 仍然可以调用父类被重写的方法}
}

相同点

  • 都是引用类型
  • 都必须在非静态方法中使用
  • 都可以调用构造方法(必须放在第一行)

不同点

特性 this super
指向对象 当前对象 父类对象
调用构造方法 调用本类其他构造方法 调用父类构造方法
访问成员变量 访问本类成员变量 访问父类成员变量
访问方法 访问本类方法 访问父类方法
使用限制 可在任何非静态方法中使用 只能在子类中使用

使用场景

this的典型使用场景

public class Employee {private String id;private String name;private double salary;// 1. 区分同名变量public Employee(String id, String name, double salary) {this.id = id;this.name = name;this.salary = salary;}// 2. 构造方法重载调用public Employee() {this("E001", "Unknown", 0.0);}// 3. 返回当前对象实现链式调用public Employee setId(String id) {this.id = id;return this;}public Employee setName(String name) {this.name = name;return this;}// 使用示例public static void main(String[] args) {Employee emp = new Employee().setId("E002").setName("John").setSalary(5000.0);}
}

super的典型使用场景

// 父类
class BankAccount {protected String accountNumber;protected double balance;public BankAccount(String accountNumber, double balance) {this.accountNumber = accountNumber;this.balance = balance;}public void deposit(double amount) {balance += amount;System.out.println("Deposited: " + amount);}public void display() {System.out.println("Account: " + accountNumber + ", Balance: " + balance);}
}// 子类
class SavingsAccount extends BankAccount {private double interestRate;public SavingsAccount(String accountNumber, double balance, double interestRate) {super(accountNumber, balance);  // 调用父类构造方法this.interestRate = interestRate;}@Overridepublic void display() {super.display();  // 调用父类方法System.out.println("Interest Rate: " + interestRate + "%");}public void applyInterest() {double interest = balance * interestRate / 100;super.deposit(interest);  // 明确调用父类方法}
}

综合示例

class Person {protected String name;protected int age;public Person(String name, int age) {this.name = name;this.age = age;}public void introduce() {System.out.println("I'm " + name + ", " + age + " years old.");}
}class Employee extends Person {private String employeeId;private double salary;public Employee(String name, int age, String employeeId, double salary) {super(name, age);  // 调用父类构造方法this.employeeId = employeeId;this.salary = salary;}@Overridepublic void introduce() {super.introduce();  // 调用父类方法System.out.println("Employee ID: " + this.employeeId);  // 使用this访问当前类成员System.out.println("Salary: $" + this.salary);}// 使用this实现方法链public Employee setSalary(double salary) {this.salary = salary;return this;}
}

注意事项

  1. 构造方法调用顺序:使用this()super()调用构造方法时,必须放在方法的第一行
  2. 不能同时使用:在同一个构造方法中不能同时使用this()super()
  3. 静态上下文:在静态方法中不能使用thissuper
  4. 继承关系super只能在有继承关系的子类中使用

包和导入

包声明

package com.example.mypackage;// 导入其他包中的类
import java.util.ArrayList;
import java.util.List;
import java.util.Date;// 静态导入
import static java.lang.Math.PI;
import static java.lang.Math.pow;public class PackageExample {private List<String> items;private Date createTime;public double calculateCircleArea(double radius) {return PI * pow(radius, 2);}
}
  • 普通导入:导入的是接口本身。在代码中可以使用短类名(如 ArrayList)而不是完全限定类名(如 java.util.ArrayList)。
  • 静态导入:导入的是类中的静态成员(静态变量或静态方法)。在代码中可以直接使用静态成员的名称,而无需通过类名来调用。
特性 普通导入 静态导入
导入目标 、接口、枚举 静态成员(静态变量、静态方法)
语法 import package.ClassName; import static package.ClassName.staticMember;
作用 简化类名的书写 省略调用静态成员时的类名
使用示例 使用 ArrayList 代替 java.util.ArrayList 使用 PIpow() 代替 Math.PIMath.pow()
可读性影响 通常提高可读性,代码更简洁 可能降低可读性,尤其是滥用时,会让人困惑某个方法或变量来自哪里

普通导入部分

import java.util.ArrayList; // 导入类
import java.util.List;      // 导入接口
import java.util.Date;      // 导入类

作用

  • 这行代码告诉编译器:“当我写下 List, ArrayList, Date 时,我指的是 java.util 包里的那些。”
  • 因此,可以在代码中直接使用:
private List<String> items;       // 而不是 java.util.List<String> items;
private Date createTime;          // 而不是 java.util.Date createTime;

如果没有普通导入,就必须使用完全限定名,代码会变得非常冗长:

private java.util.List<String> items;
private java.util.Date createTime;

静态导入部分

import static java.lang.Math.PI;  // 导入静态常量
import static java.lang.Math.pow; // 导入静态方法

作用

  • 这行代码告诉编译器:“当我写下 PIpow 时,我指的是 java.lang.Math 类中的静态常量 PI 和静态方法 pow。”
  • 因此,可以在 calculateCircleArea 方法中直接使用:
return PI * pow(radius, 2); // 而不是 Math.PI * Math.pow(radius, 2);

如果没有静态导入,就必须通过类名调用,这是更传统、更清晰的方式:

public double calculateCircleArea(double radius) {return Math.PI * Math.pow(radius, 2); // 明确指出了 PI 和 pow 的来源
}

封装性示例

封装是指将对象的属性(数据)和行为(方法)结合在一起,对外隐藏对象的内部细节,仅通过对象提供的接口与外界交互。

封装的目的是增强安全性和简化编程,使得对象更加独立。

public class BankAccount {// 私有成员变量,实现封装private String accountNumber;private String accountHolder;private double balance;private String password;public BankAccount(String accountNumber, String accountHolder, double initialBalance, String password) {this.accountNumber = accountNumber;this.accountHolder = accountHolder;this.balance = initialBalance;this.password = password;}// 公共方法提供对私有变量的受控访问public boolean deposit(double amount) {if (amount > 0) {balance += amount;return true;}return false;}public boolean withdraw(double amount, String inputPassword) {if (authenticate(inputPassword) && amount > 0 && amount <= balance) {balance -= amount;return true;}return false;}public double getBalance(String inputPassword) {if (authenticate(inputPassword)) {return balance;}return -1; // 表示认证失败}// 私有方法,内部使用private boolean authenticate(String inputPassword) {return this.password.equals(inputPassword);}// 只能获取,不能修改public String getAccountNumber() {return accountNumber;}public String getAccountHolder() {return accountHolder;}
}

复杂示例:学生管理系统设计

import java.util.ArrayList;
import java.util.List;public class Student {// 静态变量 - 学生总数private static int totalStudents = 0;// 实例变量private final int studentId;  // final变量,一旦赋值不能修改private String name;private int age;private String className;private List<Double> scores;// 静态初始化块static {System.out.println("Student类被加载");}// 实例初始化块{scores = new ArrayList<>();totalStudents++;  // 每创建一个学生对象,总数加1}// 构造方法public Student(int studentId, String name, int age, String className) {this.studentId = studentId;this.name = name;this.age = age;this.className = className;}// 各种方法public void addScore(double score) {if (score >= 0 && score <= 100) {scores.add(score);}}public double calculateAverage() {if (scores.isEmpty()) {return 0;}double sum = 0;for (double score : scores) {sum += score;}return sum / scores.size();}public String getGrade() {double average = calculateAverage();if (average >= 90) return "A";else if (average >= 80) return "B";else if (average >= 70) return "C";else if (average >= 60) return "D";else return "F";}// 静态方法public static int getTotalStudents() {return totalStudents;}// 重写toString方法@Overridepublic String toString() {return String.format("学号: %d, 姓名: %s, 年龄: %d, 班级: %s, 平均分: %.2f, 等级: %s",studentId, name, age, className, calculateAverage(), getGrade());}// getter和setter方法public int getStudentId() {return studentId;}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) {this.age = age;}}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public List<Double> getScores() {return new ArrayList<>(scores); // 返回副本,保护原始数据}
}// 使用示例
class StudentManagementSystem {public static void main(String[] args) {// 创建学生对象Student student1 = new Student(1001, "张三", 20, "计算机1班");Student student2 = new Student(1002, "李四", 21, "计算机2班");// 添加成绩student1.addScore(85);student1.addScore(92);student1.addScore(78);student2.addScore(90);student2.addScore(88);student2.addScore(95);// 显示学生信息System.out.println(student1);System.out.println(student2);// 显示学生总数System.out.println("学生总数: " + Student.getTotalStudents());}
}

不可变类

// 不可变类示例
public final class ImmutablePerson {private final String name;private final int age;private final List<String> hobbies;public ImmutablePerson(String name, int age, List<String> hobbies) {this.name = name;this.age = age;// 防御性拷贝this.hobbies = new ArrayList<>(hobbies);}public String getName() {return name;}public int getAge() {return age;}public List<String> getHobbies() {// 返回不可修改的列表return Collections.unmodifiableList(hobbies);}
}

总结

Java普通类的核心:

  1. 封装性:通过访问修饰符控制成员的可见性
  2. 构造方法:对象初始化,支持重载
  3. 成员方法:实现类的行为,支持重载
  4. 静态成员:类级别的变量和方法
  5. 代码块:初始化代码的执行
  6. this关键字:引用当前对象
  7. 包管理:组织类和命名空间

抽象类 (Abstract Class)

抽象类的定义和基本概念

抽象类定义语法

[访问修饰符] abstract class 类名 [extends 父类] [implements 接口1, 接口2, ...] {// 成员变量// 构造方法// 抽象方法// 具体方法// 代码块// 内部类
}

抽象类的基本特征

// 抽象类不能被实例化
public abstract class Animal {// 抽象方法:没有方法体,必须由子类实现public abstract void makeSound();// 具体方法:有方法体,子类可以直接使用或重写public void sleep() {System.out.println("动物正在睡觉...");}// 可以有成员变量protected String name;protected int age;// 可以有构造方法public Animal(String name, int age) {this.name = name;this.age = age;}
}

抽象方法

抽象方法的特点

public abstract class Shape {// 抽象方法:使用abstract关键字,没有方法体public abstract double calculateArea();public abstract double calculatePerimeter();// 错误示例:抽象方法不能有方法体// public abstract void wrongMethod() { } // 编译错误// 抽象方法不能是private的// private abstract void privateAbstractMethod(); // 编译错误// 抽象方法不能是static的// public static abstract void staticAbstractMethod(); // 编译错误// 抽象方法不能是final的// public final abstract void finalAbstractMethod(); // 编译错误
}

抽象方法的访问修饰符

public abstract class AccessModifierExample {// public抽象方法 - 最常见public abstract void publicAbstractMethod();// protected抽象方法 - 子类或同包可见protected abstract void protectedAbstractMethod();// 默认修饰符抽象方法 - 同包可见abstract void defaultAbstractMethod();// private抽象方法不允许// private abstract void privateAbstractMethod(); // 编译错误
}

抽象类构造方法的使用

public abstract class Vehicle {protected String brand;protected String model;protected int year;// 抽象类可以有构造方法public Vehicle(String brand, String model, int year) {this.brand = brand;this.model = model;this.year = year;System.out.println("Vehicle构造方法被调用");}// 可以有多个构造方法public Vehicle(String brand) {this(brand, "未知型号", 2020);}public abstract void start();public abstract void stop();
}// 子类必须调用父类的构造方法
class Car extends Vehicle {private int doorCount;public Car(String brand, String model, int year, int doorCount) {super(brand, model, year); // 必须调用父类构造方法this.doorCount = doorCount;}@Overridepublic void start() {System.out.println(brand + " " + model + " 汽车启动");}@Overridepublic void stop() {System.out.println(brand + " " + model + " 汽车停止");}
}

抽象类的成员变量

public abstract class MemberVariableExample {// 实例变量protected String instanceVar = "实例变量";// 静态变量public static String staticVar = "静态变量";// 常量public static final String CONSTANT_VAR = "常量";// 瞬态变量protected transient String transientVar;// volatile 变量protected volatile boolean flag;// final变量protected final String finalVar;public MemberVariableExample() {this.finalVar = "最终变量"; // 必须在构造方法中初始化final变量}
}

抽象类的具体方法

public abstract class ConcreteMethodExample {// 普通具体方法public void normalMethod() {System.out.println("这是一个普通具体方法");}// final方法 - 子类不能重写public final void finalMethod() {System.out.println("这是一个final方法");}// static方法public static void staticMethod() {System.out.println("这是一个静态方法");}// private方法private void privateMethod() {System.out.println("这是一个私有方法");}// protected方法protected void protectedMethod() {System.out.println("这是一个受保护方法");}// 模板方法模式示例public final void templateMethod() {step1();step2();step3();hookMethod(); // 钩子方法}private void step1() {System.out.println("步骤1");}private void step2() {System.out.println("步骤2");}// 抽象方法,由子类实现protected abstract void step3();// 钩子方法,子类可以选择性重写protected void hookMethod() {// 默认空实现}
}

抽象类的继承

抽象类继承抽象类

当一个抽象类继承另一个抽象类时,可以:

  • 实现部分父类的抽象方法
  • 保持其他抽象方法不变
  • 添加新的抽象方法

这种设计允许在继承链中:

  1. 提供通用实现(如所有哺乳动物睡觉方式相似)
  2. 强制特定实现(如不同动物吃的方式不同)
  3. 逐步具体化,减少代码重复

这就是面向对象设计中"抽象层次逐步具体化"的典型应用

public abstract class AbstractAnimal {protected String name;public AbstractAnimal(String name) {this.name = name;}public abstract void eat();public abstract void sleep();
}// 抽象类继承另一个抽象类
public abstract class AbstractMammal extends AbstractAnimal {protected boolean hasFur;public AbstractMammal(String name, boolean hasFur) {super(name);this.hasFur = hasFur;}// 可以实现部分抽象方法@Overridepublic void sleep() {System.out.println(name + " 正在睡觉");}// 可以添加新的抽象方法public abstract void giveBirth();// eat方法仍然保持抽象,由具体子类实现
}// 具体类继承抽象类
class Dog extends AbstractMammal {public Dog(String name, boolean hasFur) {super(name, hasFur);}@Overridepublic void eat() {System.out.println(name + " 在吃狗粮");}@Overridepublic void giveBirth() {System.out.println(name + " 生小狗");}
}

必须实现所有抽象方法

public abstract class IncompleteAbstractClass {public abstract void method1();public abstract void method2();
}// 错误示例:没有实现所有抽象方法
// class ConcreteClass1 extends IncompleteAbstractClass { // 编译错误
//     @Override
//     public void method1() { }
//     // 缺少method2的实现
// }// 正确示例:实现所有抽象方法
class ConcreteClass2 extends IncompleteAbstractClass {@Overridepublic void method1() {System.out.println("实现method1");}@Overridepublic void method2() {System.out.println("实现method2");}
}

抽象类实现接口

interface Flyable {void fly();void land();
}interface Swimmable {void swim();void dive();
}// 抽象类实现接口
public abstract class Bird implements Flyable {protected String name;protected double wingspan;public Bird(String name, double wingspan) {this.name = name;this.wingspan = wingspan;}// 实现部分接口方法@Overridepublic void land() {System.out.println(name + " 正在降落");}// fly方法保持抽象,由具体子类实现// public abstract void fly(); // 隐式存在// 可以添加自己的抽象方法public abstract void buildNest();
}// 实现多个接口
public abstract class Duck implements Flyable, Swimmable {protected String name;public Duck(String name) {this.name = name;}// 必须实现所有接口的抽象方法,或者声明为抽象@Overridepublic abstract void fly();@Overridepublic abstract void land();@Overridepublic abstract void swim();@Overridepublic abstract void dive();
}// 具体实现
class MallardDuck extends Duck {public MallardDuck(String name) {super(name);}@Overridepublic void fly() {System.out.println(name + " 在飞行");}@Overridepublic void land() {System.out.println(name + " 降落在水面上");}@Overridepublic void swim() {System.out.println(name + " 在游泳");}@Overridepublic void dive() {System.out.println(name + " 在潜水");}
}

经典模板方法模式

public abstract class DataProcessor {// 模板方法 - 定义算法骨架public final void process() {readData();processData();writeData();if (needValidation()) {validateData();}}// 具体方法private void readData() {System.out.println("读取数据...");}private void writeData() {System.out.println("写入数据...");}// 抽象方法 - 由子类实现protected abstract void processData();// 钩子方法 - 子类可以选择性重写protected boolean needValidation() {return false;}protected void validateData() {System.out.println("验证数据...");}
}// 具体实现
class CSVProcessor extends DataProcessor {@Overrideprotected void processData() {System.out.println("处理CSV数据...");}@Overrideprotected boolean needValidation() {return true;}@Overrideprotected void validateData() {System.out.println("验证CSV数据格式...");}
}class XMLProcessor extends DataProcessor {@Overrideprotected void processData() {System.out.println("处理XML数据...");}
}

复杂示例:图形系统

import java.awt.Color;public abstract class GraphicObject {// 成员变量protected int x, y;protected Color color;protected boolean visible;// 静态变量protected static int objectCount = 0;// 构造方法public GraphicObject(int x, int y, Color color) {this.x = x;this.y = y;this.color = color;this.visible = true;objectCount++;}// 抽象方法public abstract void draw();public abstract void resize(double scale);public abstract double calculateArea();public abstract double calculatePerimeter();// 具体方法public void move(int newX, int newY) {this.x = newX;this.y = newY;System.out.println("图形移动到 (" + x + ", " + y + ")");}public void setColor(Color newColor) {this.color = newColor;System.out.println("颜色已更改");}public void show() {this.visible = true;System.out.println("图形显示");}public void hide() {this.visible = false;System.out.println("图形隐藏");}// final方法public final String getPosition() {return "(" + x + ", " + y + ")";}// 静态方法public static int getObjectCount() {return objectCount;}// 模板方法public final void render() {if (visible) {System.out.println("开始渲染图形...");draw();System.out.println("图形渲染完成");} else {System.out.println("图形不可见,跳过渲染");}}
}// 具体实现 - 圆形
class Circle extends GraphicObject {private double radius;public Circle(int x, int y, Color color, double radius) {super(x, y, color);this.radius = radius;}@Overridepublic void draw() {System.out.println("绘制圆形: 中心(" + x + ", " + y + "), 半径=" + radius + ", 颜色=" + color);}@Overridepublic void resize(double scale) {this.radius *= scale;System.out.println("圆形缩放,新半径: " + radius);}@Overridepublic double calculateArea() {return Math.PI * radius * radius;}@Overridepublic double calculatePerimeter() {return 2 * Math.PI * radius;}// 特有的方法public double getDiameter() {return 2 * radius;}
}// 具体实现 - 矩形
class Rectangle extends GraphicObject {private double width, height;public Rectangle(int x, int y, Color color, double width, double height) {super(x, y, color);this.width = width;this.height = height;}@Overridepublic void draw() {System.out.println("绘制矩形: 左上角(" + x + ", " + y + "), 宽=" + width + ", 高=" + height + ", 颜色=" + color);}@Overridepublic void resize(double scale) {this.width *= scale;this.height *= scale;System.out.println("矩形缩放,新尺寸: " + width + "x" + height);}@Overridepublic double calculateArea() {return width * height;}@Overridepublic double calculatePerimeter() {return 2 * (width + height);}// 特有的方法public boolean isSquare() {return width == height;}
}

抽象类的设计模式 - 工厂方法模式

public abstract class Document {protected String title;protected String content;public Document(String title) {this.title = title;}// 抽象工厂方法public abstract void create();public abstract void save();public abstract void print();// 模板方法public final void processDocument() {create();edit();save();print();}// 钩子方法protected void edit() {System.out.println("编辑文档: " + title);}
}// 具体文档类型
class WordDocument extends Document {public WordDocument(String title) {super(title);}@Overridepublic void create() {System.out.println("创建Word文档: " + title);this.content = "Word文档内容";}@Overridepublic void save() {System.out.println("保存Word文档为 .docx 格式");}@Overridepublic void print() {System.out.println("打印Word文档");}@Overrideprotected void edit() {super.edit();System.out.println("使用Word特定功能编辑");}
}class PDFDocument extends Document {public PDFDocument(String title) {super(title);}@Overridepublic void create() {System.out.println("创建PDF文档: " + title);this.content = "PDF文档内容";}@Overridepublic void save() {System.out.println("保存PDF文档为 .pdf 格式");}@Overridepublic void print() {System.out.println("打印PDF文档(优化打印质量)");}
}

选择抽象类的情况

// 适合使用抽象类的场景:// 1. 需要共享代码
public abstract class DatabaseService {protected Connection connection;// 共享的具体方法protected void connect(String url, String username, String password) {System.out.println("连接到数据库: " + url);// 连接逻辑...}protected void disconnect() {System.out.println("断开数据库连接");// 断开逻辑...}// 抽象方法public abstract void executeQuery(String query);public abstract void createTable(String tableName);
}// 2. 需要定义模板方法
public abstract class Game {// 模板方法public final void play() {initialize();startPlay();endPlay();}protected abstract void initialize();protected abstract void startPlay();protected abstract void endPlay();
}// 3. 需要维护状态
public abstract class StatefulComponent {protected State currentState;protected List<State> stateHistory;public StatefulComponent() {this.stateHistory = new ArrayList<>();}public abstract void transitionTo(State newState);public abstract boolean isValidTransition(State newState);
}

设计原则

// 1. 合理设计抽象级别
public abstract class PaymentProcessor {protected double amount;protected String currency;public PaymentProcessor(double amount, String currency) {this.amount = amount;this.currency = currency;}// 适度的抽象 - 所有支付方式都需要的方法public abstract boolean validatePayment();public abstract String processPayment();public abstract String getPaymentMethod();// 具体方法 - 共享逻辑protected final String formatAmount() {return String.format("%.2f %s", amount, currency);}// 模板方法public final String executePayment() {if (validatePayment()) {return processPayment();} else {return "支付验证失败";}}
}// 2. 避免过度抽象
public abstract class SimpleAbstractClass {// 好的抽象:有明确的抽象目的public abstract void performAction();// 避免:只有一个抽象方法的抽象类,考虑使用接口// public abstract void singleMethod();
}

总结

Java抽象类的核心要点:

  1. 定义:使用abstract关键字,不能实例化
  2. 抽象方法:没有方法体,必须由子类实现
  3. 构造方法:可以有,用于子类初始化
  4. 具体方法:可以有实现的方法
  5. 继承规则:必须实现所有抽象方法,或者声明为抽象类
  6. 设计模式:常用于模板方法模式、工厂方法模式等
  7. 与接口比较:适合共享代码、维护状态、定义模板方法的场景

接口 (Interface)

接口的定义和基本概念

接口定义语法

[访问修饰符] interface 接口名 [extends 父接口1, 父接口2, ...] {// 常量// 抽象方法// 默认方法 (Java 8+)// 静态方法 (Java 8+)// 私有方法 (Java 9+)
}

接口的基本特征

// 基本接口定义
public interface Animal {// 常量 (默认是 public static final)String KINGDOM = "Animalia";// 抽象方法 (默认是 public abstract)void makeSound();void eat();// 默认方法 (Java 8+)default void sleep() {System.out.println("动物正在睡觉...");}// 静态方法 (Java 8+)static void displayKingdom() {System.out.println("动物界: " + KINGDOM);}
}

接口的常量定义和特点

public interface ConstantsExample {// 以下三种定义方式是等价的int MAX_SIZE = 100;                    // 默认 public static finalpublic static final int MIN_SIZE = 1;  // 显式声明public int DEFAULT_SIZE = 10;          // 省略 static final// 复杂常量String[] VALID_TYPES = {"TYPE_A", "TYPE_B", "TYPE_C"};List<String> CATEGORIES = List.of("CAT1", "CAT2", "CAT3");// 编译时常量double PI = 3.14159;long TIMEOUT = 5000L;
}// 使用接口常量
class ConstantUser {public void process() {System.out.println("最大尺寸: " + ConstantsExample.MAX_SIZE);System.out.println("默认尺寸: " + ConstantsExample.DEFAULT_SIZE);}
}

抽象方法的定义

public interface MethodExample {// 以下定义方式是等价的void method1();                    // 默认 public abstractpublic abstract void method2();    // 显式声明abstract void method3();           // 省略 public// 带参数和返回值的方法String getName();void setName(String name);boolean isValid(int value);double calculate(double x, double y);// 注意:不能有方法体// void wrongMethod() { } // 编译错误
}// 实现接口
class MethodExampleImpl implements MethodExample {private String name;@Overridepublic void method1() {System.out.println("实现 method1");}@Overridepublic void method2() {System.out.println("实现 method2");}@Overridepublic void method3() {System.out.println("实现 method3");}@Overridepublic String getName() {return name;}@Overridepublic void setName(String name) {this.name = name;}@Overridepublic boolean isValid(int value) {return value > 0;}@Overridepublic double calculate(double x, double y) {return x + y;}
}

默认方法 (Java 8+)

默认方法的定义和使用

public interface DefaultMethodExample {// 抽象方法void performAction();// 默认方法 - 有方法体default void logAction(String action) {System.out.println("执行动作: " + action);System.out.println("时间: " + java.time.LocalDateTime.now());}default String getDefaultName() {return "默认名称";}// 默认方法可以调用其他方法default void performWithLog() {logAction("开始执行");performAction();logAction("执行完成");}// 默认方法可以重写Object类的方法,但不推荐@Overridedefault String toString() {return "DefaultMethodExample实例";}
}// 实现类可以选择重写默认方法
class DefaultMethodImpl implements DefaultMethodExample {@Overridepublic void performAction() {System.out.println("执行具体动作");}// 可选:重写默认方法@Overridepublic String getDefaultName() {return "自定义名称";}
}// 实现类也可以不重写默认方法
class SimpleImpl implements DefaultMethodExample {@Overridepublic void performAction() {System.out.println("简单实现");}// 使用接口提供的默认方法
}

默认方法的多继承冲突

interface InterfaceA {default void conflictMethod() {System.out.println("来自 InterfaceA");}
}interface InterfaceB {default void conflictMethod() {System.out.println("来自 InterfaceB");}
}// 编译错误:默认方法冲突
// class ConflictClass implements InterfaceA, InterfaceB { }// 解决方案1:重写冲突方法
class Solution1 implements InterfaceA, InterfaceB {@Overridepublic void conflictMethod() {System.out.println("重写冲突方法");// 可以选择调用特定的接口方法InterfaceA.super.conflictMethod();}
}// 解决方案2:选择其中一个接口
class Solution2 implements InterfaceA {// 使用 InterfaceA 的默认方法
}interface InterfaceC extends InterfaceA {// 解决方案3:在接口中重写@Overridedefault void conflictMethod() {System.out.println("InterfaceC 重写");}
}

静态方法 (Java 8+)

public interface StaticMethodExample {// 静态方法static String createId() {return "ID-" + System.currentTimeMillis();}static boolean isValidEmail(String email) {return email != null && email.contains("@");}static double calculateCircleArea(double radius) {return Math.PI * radius * radius;}// 静态方法可以调用其他静态方法static void validateAndProcess(String email) {if (isValidEmail(email)) {System.out.println("处理邮箱: " + email);} else {System.out.println("无效邮箱");}}// 抽象方法void instanceMethod();
}// 使用静态方法
class StaticMethodUser {public void demo() {// 通过接口名直接调用静态方法String id = StaticMethodExample.createId();boolean valid = StaticMethodExample.isValidEmail("test@example.com");double area = StaticMethodExample.calculateCircleArea(5.0);System.out.println("ID: " + id);System.out.println("邮箱有效: " + valid);System.out.println("面积: " + area);}
}// 实现类不能继承接口的静态方法
class StaticMethodImpl implements StaticMethodExample {@Overridepublic void instanceMethod() {// 不能这样调用:this.createId(); // 错误// 必须通过接口名调用String id = StaticMethodExample.createId();System.out.println("使用ID: " + id);}
}

私有方法 (Java 9+)

public interface PrivateMethodExample {// 默认方法default void complexOperation() {validateInput();step1();step2();cleanup();}default void anotherOperation() {validateInput();// 其他操作...cleanup();}// 私有方法 - 辅助方法private void validateInput() {System.out.println("验证输入...");// 验证逻辑}private void step1() {System.out.println("执行步骤1...");// 步骤1逻辑}private void step2() {System.out.println("执行步骤2...");// 步骤2逻辑}private void cleanup() {System.out.println("清理资源...");// 清理逻辑}// 私有静态方法private static String generateInternalId() {return "INTERNAL_" + System.nanoTime();}static String createInternalResource() {String id = generateInternalId();System.out.println("创建资源: " + id);return id;}
}// 实现类
class PrivateMethodImpl implements PrivateMethodExample {// 私有方法对实现类不可见// 只能使用默认方法
}

接口的继承

接口继承接口

interface BasicAnimal {void eat();void sleep();
}interface Mammal extends BasicAnimal {void giveBirth();default void breathe() {System.out.println("用肺呼吸");}
}interface Swimmer {void swim();
}// 多重继承
interface AquaticMammal extends Mammal, Swimmer {void dive();@Overridedefault void breathe() {System.out.println("浮出水面呼吸");}
}// 具体实现
class Dolphin implements AquaticMammal {@Overridepublic void eat() {System.out.println("吃鱼");}@Overridepublic void sleep() {System.out.println("水中睡觉");}@Overridepublic void giveBirth() {System.out.println("生小海豚");}@Overridepublic void swim() {System.out.println("快速游泳");}@Overridepublic void dive() {System.out.println("深潜");}
}

复杂的接口继承

interface Readable {String read();default void open() {System.out.println("打开资源");}
}interface Writable {void write(String content);default void open() {System.out.println("打开写入流");}
}// 解决默认方法冲突
interface ReadWritable extends Readable, Writable {// 必须解决 open() 方法的冲突@Overridedefault void open() {System.out.println("打开读写流");Readable.super.open();  // 调用 Readable 的 openWritable.super.open();  // 调用 Writable 的 open}// 添加新方法void flush();
}class FileProcessor implements ReadWritable {private String content = "";@Overridepublic String read() {return content;}@Overridepublic void write(String content) {this.content = content;}@Overridepublic void flush() {System.out.println("刷新缓冲区");}
}

类实现多个接口

interface Flyable {void fly();default void takeOff() {System.out.println("起飞");}
}interface Swimmable {void swim();default void dive() {System.out.println("潜水");}
}interface Runnable {void run();default void jump() {System.out.println("跳跃");}
}// 实现多个接口
class Duck implements Flyable, Swimmable, Runnable {private String name;public Duck(String name) {this.name = name;}@Overridepublic void fly() {System.out.println(name + " 在飞行");}@Overridepublic void swim() {System.out.println(name + " 在游泳");}@Overridepublic void run() {System.out.println(name + " 在奔跑");}// 可以重写默认方法@Overridepublic void takeOff() {System.out.println(name + " 从水面起飞");}
}// 使用多态
class MultiInterfaceDemo {public static void main(String[] args) {Duck duck = new Duck("唐老鸭");// 作为 Flyable 使用Flyable flyable = duck;flyable.fly();flyable.takeOff();// 作为 Swimmable 使用Swimmable swimmable = duck;swimmable.swim();swimmable.dive();// 作为 Runnable 使用Runnable runnable = duck;runnable.run();runnable.jump();}
}

函数式接口

函数式接口定义

// 函数式接口:只有一个抽象方法
@FunctionalInterface
interface Calculator {int calculate(int a, int b);// 可以有默认方法default void printResult(int result) {System.out.println("结果: " + result);}// 可以有静态方法static Calculator create() {return (a, b) -> a + b;}// 不能有第二个抽象方法// void anotherAbstractMethod(); // 编译错误
}// 使用函数式接口
class FunctionalInterfaceDemo {public static void main(String[] args) {// 使用 Lambda 表达式Calculator adder = (a, b) -> a + b;Calculator multiplier = (a, b) -> a * b;System.out.println("加法: " + adder.calculate(5, 3));System.out.println("乘法: " + multiplier.calculate(5, 3));// 使用方法引用Calculator anotherAdder = Integer::sum;System.out.println("另一种加法: " + anotherAdder.calculate(5, 3));}
}

常见的函数式接口

import java.util.function.*;public class CommonFunctionalInterfaces {// Predicate - 接受一个参数,返回booleanPredicate<String> isLong = s -> s.length() > 5;// Function - 接受一个参数,返回一个结果Function<String, Integer> stringToInt = Integer::parseInt;// Consumer - 接受一个参数,没有返回值Consumer<String> printer = System.out::println;// Supplier - 没有参数,返回一个结果Supplier<Double> randomSupplier = Math::random;// UnaryOperator - 接受一个参数,返回同类型结果UnaryOperator<String> toupper = String::toUpperCase;// BinaryOperator - 接受两个同类型参数,返回同类型结果BinaryOperator<Integer> adder = Integer::sum;public void demo() {System.out.println("是否长字符串: " + isLong.test("Hello World"));System.out.println("字符串转数字: " + stringToInt.apply("123"));printer.accept("Hello Consumer");System.out.println("随机数: " + randomSupplier.get());System.out.println("转大写: " + toupper.apply("hello"));System.out.println("相加: " + adder.apply(5, 3));}
}

标记接口

// 标记接口:没有任何方法的接口
interface Serializable {// 空接口
}interface Cloneable {// 空接口
}interface Remote {// 空接口
}// 自定义标记接口
interface Loggable {// 标记需要记录日志的类
}interface Cacheable {// 标记可以缓存的类
}// 使用标记接口
class User implements Loggable, Cacheable {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}// 根据标记接口执行不同逻辑public void process(Object obj) {if (obj instanceof Loggable) {System.out.println("记录操作日志");}if (obj instanceof Cacheable) {System.out.println("加入缓存");}}
}

复杂示例:支付系统接口设计

import java.math.BigDecimal;
import java.time.LocalDateTime;// 支付接口
public interface Payment {// 常量BigDecimal MAX_AMOUNT = new BigDecimal("1000000");String DEFAULT_CURRENCY = "CNY";// 抽象方法String processPayment(BigDecimal amount, String currency);boolean validatePayment();String getPaymentId();// 默认方法default String getTimestamp() {return LocalDateTime.now().toString();}default boolean validateAmount(BigDecimal amount) {return amount != null && amount.compareTo(BigDecimal.ZERO) > 0 && amount.compareTo(MAX_AMOUNT) <= 0;}default String formatAmount(BigDecimal amount, String currency) {return String.format("%s %.2f", currency, amount);}// 静态方法static String generateTransactionId() {return "TXN_" + System.currentTimeMillis() + "_" + (int)(Math.random() * 1000);}static boolean isValidCurrency(String currency) {return currency != null && (currency.equals("CNY") || currency.equals("USD") || currency.equals("EUR"));}
}// 退款接口
interface Refundable extends Payment {String processRefund(BigDecimal amount, String reason);@Overridedefault boolean validatePayment() {System.out.println("验证可退款支付");return true;}
}// 国际支付接口
interface InternationalPayment extends Payment {double getExchangeRate(String fromCurrency, String toCurrency);BigDecimal calculateFee(BigDecimal amount);@Overridedefault String processPayment(BigDecimal amount, String currency) {if (!isValidCurrency(currency)) {return "不支持货币: " + currency;}BigDecimal fee = calculateFee(amount);BigDecimal total = amount.add(fee);return String.format("国际支付: %s, 手续费: %s, 总计: %s",formatAmount(amount, currency),formatAmount(fee, currency),formatAmount(total, currency));}
}// 具体实现 - 支付宝支付
class AlipayPayment implements Refundable {private String paymentId;public AlipayPayment() {this.paymentId = Payment.generateTransactionId();}@Overridepublic String processPayment(BigDecimal amount, String currency) {if (!validateAmount(amount)) {return "金额无效";}if (!isValidCurrency(currency)) {return "货币无效";}return String.format("支付宝支付成功: ID=%s, 金额=%s, 时间=%s",paymentId, formatAmount(amount, currency), getTimestamp());}@Overridepublic boolean validatePayment() {System.out.println("验证支付宝支付");return true;}@Overridepublic String getPaymentId() {return paymentId;}@Overridepublic String processRefund(BigDecimal amount, String reason) {return String.format("支付宝退款: 金额=%s, 原因=%s, 时间=%s",formatAmount(amount, DEFAULT_CURRENCY), reason, getTimestamp());}
}// 具体实现 - PayPal支付
class PayPalPayment implements InternationalPayment {private String paymentId;public PayPalPayment() {this.paymentId = Payment.generateTransactionId();}@Overridepublic String processPayment(BigDecimal amount, String currency) {// 使用接口的默认实现String result = InternationalPayment.super.processPayment(amount, currency);return "PayPal " + result;}@Overridepublic boolean validatePayment() {System.out.println("验证PayPal支付");return true;}@Overridepublic String getPaymentId() {return paymentId;}@Overridepublic double getExchangeRate(String fromCurrency, String toCurrency) {// 模拟汇率if ("USD".equals(fromCurrency) && "CNY".equals(toCurrency)) {return 6.5;}return 1.0;}@Overridepublic BigDecimal calculateFee(BigDecimal amount) {// 手续费为金额的3.5%return amount.multiply(new BigDecimal("0.035"));}
}

接口与策略模式

// 策略接口
interface SortingStrategy {void sort(int[] array);default void printArray(int[] array) {for (int num : array) {System.out.print(num + " ");}System.out.println();}
}// 具体策略
class BubbleSort implements SortingStrategy {@Overridepublic void sort(int[] array) {System.out.println("使用冒泡排序");for (int i = 0; i < array.length - 1; i++) {for (int j = 0; j < array.length - 1 - i; j++) {if (array[j] > array[j + 1]) {int temp = array[j];array[j] = array[j + 1];array[j + 1] = temp;}}}}
}class QuickSort implements SortingStrategy {@Overridepublic void sort(int[] array) {System.out.println("使用快速排序");quickSort(array, 0, array.length - 1);}private void quickSort(int[] array, int low, int high) {if (low < high) {int pivot = partition(array, low, high);quickSort(array, low, pivot - 1);quickSort(array, pivot + 1, high);}}private int partition(int[] array, int low, int high) {int pivot = array[high];int i = low - 1;for (int j = low; j < high; j++) {if (array[j] <= pivot) {i++;int temp = array[i];array[i] = array[j];array[j] = temp;}}int temp = array[i + 1];array[i + 1] = array[high];array[high] = temp;return i + 1;}
}// 上下文类
class Sorter {private SortingStrategy strategy;public Sorter(SortingStrategy strategy) {this.strategy = strategy;}public void setStrategy(SortingStrategy strategy) {this.strategy = strategy;}public void sortArray(int[] array) {System.out.println("排序前:");strategy.printArray(array);strategy.sort(array);System.out.println("排序后:");strategy.printArray(array);}
}

接口设计原则

// 1. 接口隔离原则 - 多个专用接口优于一个通用接口
interface Printer {void print();
}interface Scanner {void scan();
}interface Fax {void fax();
}// 而不是一个大的接口
// interface AllInOne { void print(); void scan(); void fax(); }// 2. 依赖倒置原则 - 依赖于抽象而不是具体
interface DataService {String fetchData();
}class DatabaseService implements DataService {@Overridepublic String fetchData() {return "数据库数据";}
}class ApiService implements DataService {@Overridepublic String fetchData() {return "API数据";}
}class BusinessLogic {private DataService dataService;public BusinessLogic(DataService dataService) {this.dataService = dataService; // 依赖于抽象}public void process() {String data = dataService.fetchData();System.out.println("处理: " + data);}
}

总结

Java接口的核心要点:

  1. 定义:使用interface关键字,支持多继承
  2. 常量:默认public static final
  3. 抽象方法:默认public abstract
  4. 默认方法:Java 8+,有方法体,可被重写
  5. 静态方法:Java 8+,通过接口名调用
  6. 私有方法:Java 9+,接口内部使用
  7. 函数式接口:只有一个抽象方法,支持Lambda
  8. 标记接口:没有任何方法的接口
  9. 设计模式:广泛应用于策略模式、工厂模式等

枚举 (Enum)

枚举的定义和基本概念

枚举定义语法

[访问修饰符] enum 枚举名 [implements 接口1, 接口2, ...] {// 枚举常量// 成员变量// 构造方法// 成员方法// 抽象方法
}

基本枚举示例

// 最简单的枚举
public enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}// 使用枚举
class EnumDemo {public static void main(String[] args) {Day today = Day.MONDAY;System.out.println("Today is: " + today);// 遍历所有枚举值for (Day day : Day.values()) {System.out.println(day);}}
}

枚举的成员变量和构造方法

public enum Planet {// 枚举常量,调用构造方法MERCURY(3.303e+23, 2.4397e6),VENUS(4.869e+24, 6.0518e6),EARTH(5.976e+24, 6.37814e6),MARS(6.421e+23, 3.3972e6),JUPITER(1.9e+27, 7.1492e7),SATURN(5.688e+26, 6.0268e7),URANUS(8.686e+25, 2.5559e7),NEPTUNE(1.024e+26, 2.4746e7);// 成员变量private final double mass;   // 质量(千克)private final double radius; // 半径(米)// 构造方法 - 必须是private(默认就是private,不能是public)Planet(double mass, double radius) {this.mass = mass;this.radius = radius;}// 计算方法public double surfaceGravity() {final double G = 6.67300E-11; // 万有引力常数return G * mass / (radius * radius);}public double surfaceWeight(double otherMass) {return otherMass * surfaceGravity();}// Getter方法public double getMass() {return mass;}public double getRadius() {return radius;}
}// 使用带属性的枚举
class PlanetDemo {public static void main(String[] args) {double earthWeight = 175; // 地球上的重量(磅)double mass = earthWeight / Planet.EARTH.surfaceGravity();for (Planet p : Planet.values()) {System.out.printf("在 %s 上的重量是 %.2f 磅%n",p, p.surfaceWeight(mass));}}
}

枚举的实例方法和静态方法

public enum Operation {PLUS, MINUS, TIMES, DIVIDE;// 实例方法public double calculate(double x, double y) {switch (this) {case PLUS:   return x + y;case MINUS:  return x - y;case TIMES:  return x * y;case DIVIDE: return x / y;default: throw new AssertionError("未知操作: " + this);}}// 静态方法public static Operation fromSymbol(String symbol) {switch (symbol) {case "+": return PLUS;case "-": return MINUS;case "*": return TIMES;case "/": return DIVIDE;default: throw new IllegalArgumentException("未知符号: " + symbol);}}// 重写toString方法@Overridepublic String toString() {switch (this) {case PLUS:   return "+";case MINUS:  return "-";case TIMES:  return "*";case DIVIDE: return "/";default: return name();}}
}// 使用方法
class OperationDemo {public static void main(String[] args) {double result = Operation.PLUS.calculate(10, 5);System.out.println("10 + 5 = " + result);Operation op = Operation.fromSymbol("*");System.out.println("操作符: " + op);System.out.println("10 * 5 = " + op.calculate(10, 5));}
}

枚举实现接口

// 定义接口
interface Describable {String getDescription();String getColor();
}// 枚举实现接口
public enum TrafficLight implements Describable {RED("停止", "红色") {@Overridepublic TrafficLight next() {return GREEN;}},YELLOW("警告", "黄色") {@Overridepublic TrafficLight next() {return RED;}},GREEN("通行", "绿色") {@Overridepublic TrafficLight next() {return YELLOW;}};private final String description;private final String color;TrafficLight(String description, String color) {this.description = description;this.color = color;}// 实现接口方法@Overridepublic String getDescription() {return description;}@Overridepublic String getColor() {return color;}// 抽象方法 - 每个枚举常量必须实现public abstract TrafficLight next();// 实例方法public void showStatus() {System.out.println(color + "灯: " + description);}
}// 使用枚举
class TrafficLightDemo {public static void main(String[] args) {TrafficLight light = TrafficLight.RED;for (int i = 0; i < 5; i++) {light.showStatus();light = light.next();}// 作为接口类型使用Describable describable = TrafficLight.GREEN;System.out.println("描述: " + describable.getDescription());}
}

枚举中的抽象方法

public enum Calculator {ADD {@Overridepublic double apply(double x, double y) {return x + y;}@Overridepublic String getSymbol() {return "+";}},SUBTRACT {@Overridepublic double apply(double x, double y) {return x - y;}@Overridepublic String getSymbol() {return "-";}},MULTIPLY {@Overridepublic double apply(double x, double y) {return x * y;}@Overridepublic String getSymbol() {return "*";}},DIVIDE {@Overridepublic double apply(double x, double y) {if (y == 0) throw new ArithmeticException("除数不能为零");return x / y;}@Overridepublic String getSymbol() {return "/";}};// 抽象方法 - 每个枚举常量必须实现public abstract double apply(double x, double y);public abstract String getSymbol();// 通用方法public void calculateAndPrint(double x, double y) {try {double result = apply(x, y);System.out.printf("%.2f %s %.2f = %.2f%n", x, getSymbol(), y, result);} catch (ArithmeticException e) {System.out.println("计算错误: " + e.getMessage());}}
}// 使用枚举
class CalculatorDemo {public static void main(String[] args) {Calculator.ADD.calculateAndPrint(10, 5);Calculator.DIVIDE.calculateAndPrint(10, 0); // 会捕获异常}
}

枚举的内置方法

public enum Status {PENDING, PROCESSING, COMPLETED, FAILED, CANCELLED
}class EnumMethodsDemo {public static void main(String[] args) {// values() - 获取所有枚举值Status[] allStatus = Status.values();System.out.println("所有状态:");for (Status status : allStatus) {System.out.println(status);}// valueOf() - 根据名称获取枚举实例Status status1 = Status.valueOf("COMPLETED");System.out.println("获取的状态: " + status1);// name() - 获取枚举常量的名称System.out.println("名称: " + status1.name());// ordinal() - 获取枚举常量的序号System.out.println("序号: " + status1.ordinal());// compareTo() - 比较枚举常量的顺序Status status2 = Status.PENDING;System.out.println("比较结果: " + status1.compareTo(status2));// toString() - 返回枚举常量的名称System.out.println("字符串表示: " + status1.toString());// getDeclaringClass() - 获取枚举类System.out.println("声明类: " + status1.getDeclaringClass());}
}

枚举在switch语句中的使用

public enum Command {START, STOP, PAUSE, RESUME, EXIT
}class CommandProcessor {public void processCommand(Command command) {switch (command) {case START:System.out.println("启动系统...");break;case STOP:System.out.println("停止系统...");break;case PAUSE:System.out.println("暂停系统...");break;case RESUME:System.out.println("恢复系统...");break;case EXIT:System.out.println("退出系统...");System.exit(0);break;default:System.out.println("未知命令");}}// 使用增强的switch表达式(Java 14+)public String getCommandDescription(Command command) {return switch (command) {case START -> "启动操作";case STOP -> "停止操作";case PAUSE -> "暂停操作";case RESUME -> "恢复操作";case EXIT -> "退出操作";// 不需要default,因为枚举值已经全部覆盖};}
}class SwitchDemo {public static void main(String[] args) {CommandProcessor processor = new CommandProcessor();processor.processCommand(Command.START);System.out.println(processor.getCommandDescription(Command.PAUSE));}
}

枚举集合类EnumSet和EnumMap

import java.util.EnumSet;
import java.util.EnumMap;public enum UserRole {ADMIN, MODERATOR, USER, GUEST, DEVELOPER, TESTER
}class EnumCollectionsDemo {public static void main(String[] args) {// EnumSet - 专门为枚举设计的高效Set实现EnumSet<UserRole> adminRoles = EnumSet.of(UserRole.ADMIN, UserRole.MODERATOR);EnumSet<UserRole> allRoles = EnumSet.allOf(UserRole.class);EnumSet<UserRole> developerRoles = EnumSet.range(UserRole.DEVELOPER, UserRole.TESTER);System.out.println("管理员角色: " + adminRoles);System.out.println("所有角色: " + allRoles);System.out.println("开发相关角色: " + developerRoles);// 判断包含System.out.println("包含ADMIN: " + adminRoles.contains(UserRole.ADMIN));System.out.println("包含GUEST: " + adminRoles.contains(UserRole.GUEST));// EnumMap - 专门为枚举设计的高效Map实现EnumMap<UserRole, String> roleDescriptions = new EnumMap<>(UserRole.class);roleDescriptions.put(UserRole.ADMIN, "系统管理员");roleDescriptions.put(UserRole.USER, "普通用户");roleDescriptions.put(UserRole.GUEST, "访客");System.out.println("角色描述:");for (UserRole role : roleDescriptions.keySet()) {System.out.println(role + ": " + roleDescriptions.get(role));}// 复杂的EnumSet操作EnumSet<UserRole> privilegedRoles = EnumSet.complementOf(EnumSet.of(UserRole.USER, UserRole.GUEST));System.out.println("特权角色: " + privilegedRoles);}
}

枚举实现单例模式

// 使用枚举实现单例 - 线程安全,防止反射攻击
public enum Singleton {INSTANCE;// 成员变量private int value;private String data;// 构造方法Singleton() {this.value = 0;this.data = "默认数据";System.out.println("Singleton实例被创建");}// 业务方法public void doSomething() {System.out.println("单例方法执行, value: " + value);}public void increment() {value++;}// Getter和Setterpublic int getValue() {return value;}public void setValue(int value) {this.value = value;}public String getData() {return data;}public void setData(String data) {this.data = data;}
}// 使用单例
class SingletonDemo {public static void main(String[] args) {Singleton instance1 = Singleton.INSTANCE;Singleton instance2 = Singleton.INSTANCE;System.out.println("是否是同一个实例: " + (instance1 == instance2));instance1.doSomething();instance1.increment();instance2.doSomething(); // 可以看到value增加了}
}

枚举实现策略模式

public enum NotificationType {EMAIL {@Overridepublic void sendNotification(String message, String recipient) {System.out.println("发送邮件到 " + recipient + ": " + message);}@Overridepublic boolean validateRecipient(String recipient) {return recipient != null && recipient.contains("@");}},SMS {@Overridepublic void sendNotification(String message, String recipient) {System.out.println("发送短信到 " + recipient + ": " + message);}@Overridepublic boolean validateRecipient(String recipient) {return recipient != null && recipient.matches("\\d{11}");}},PUSH {@Overridepublic void sendNotification(String message, String recipient) {System.out.println("发送推送通知到设备 " + recipient + ": " + message);}@Overridepublic boolean validateRecipient(String recipient) {return recipient != null && recipient.startsWith("device_");}},SLACK {@Overridepublic void sendNotification(String message, String recipient) {System.out.println("发送Slack消息到频道 " + recipient + ": " + message);}@Overridepublic boolean validateRecipient(String recipient) {return recipient != null && recipient.startsWith("#");}};// 抽象方法public abstract void sendNotification(String message, String recipient);public abstract boolean validateRecipient(String recipient);// 默认方法public void sendSecureNotification(String message, String recipient) {if (validateRecipient(recipient)) {String encryptedMessage = encrypt(message);sendNotification(encryptedMessage, recipient);} else {System.out.println("无效的接收者: " + recipient);}}private String encrypt(String message) {// 简单的加密演示return "[加密]" + message + "[/加密]";}// 静态工具方法public static NotificationType fromString(String type) {try {return valueOf(type.toUpperCase());} catch (IllegalArgumentException e) {throw new IllegalArgumentException("不支持的通知类型: " + type);}}
}// 使用策略枚举
class NotificationService {public void sendNotification(NotificationType type, String message, String recipient) {type.sendSecureNotification(message, recipient);}public static void main(String[] args) {NotificationService service = new NotificationService();service.sendNotification(NotificationType.EMAIL, "Hello World", "test@example.com");service.sendNotification(NotificationType.SMS, "Hello World", "13800138000");service.sendNotification(NotificationType.PUSH, "Hello World", "device_12345");service.sendNotification(NotificationType.SLACK, "Hello World", "#general");// 测试无效的接收者service.sendNotification(NotificationType.EMAIL, "Test", "invalid-email");}
}

枚举实现状态机

public enum OrderStatus {// 订单状态流转CREATED {@Overridepublic OrderStatus next() {return PAID;}@Overridepublic boolean canCancel() {return true;}},PAID {@Overridepublic OrderStatus next() {return SHIPPED;}@Overridepublic boolean canCancel() {return true;}},SHIPPED {@Overridepublic OrderStatus next() {return DELIVERED;}@Overridepublic boolean canCancel() {return false;}},DELIVERED {@Overridepublic OrderStatus next() {return COMPLETED;}@Overridepublic boolean canCancel() {return false;}},COMPLETED {@Overridepublic OrderStatus next() {return this; // 最终状态,不能再转换}@Overridepublic boolean canCancel() {return false;}},CANCELLED {@Overridepublic OrderStatus next() {return this; // 最终状态}@Overridepublic boolean canCancel() {return false;}};// 抽象方法public abstract OrderStatus next();public abstract boolean canCancel();// 状态转换方法public OrderStatus transitionToNext() {if (this == COMPLETED || this == CANCELLED) {throw new IllegalStateException("状态 " + this + " 是最终状态,不能转换");}return next();}public OrderStatus cancel() {if (!canCancel()) {throw new IllegalStateException("状态 " + this + " 不能取消");}return CANCELLED;}// 判断方法public boolean isFinal() {return this == COMPLETED || this == CANCELLED;}public boolean isActive() {return !isFinal();}
}// 订单类
class Order {private String orderId;private OrderStatus status;public Order(String orderId) {this.orderId = orderId;this.status = OrderStatus.CREATED;}public void proceedToNext() {try {this.status = status.transitionToNext();System.out.println("订单 " + orderId + " 状态变为: " + status);} catch (IllegalStateException e) {System.out.println("状态转换失败: " + e.getMessage());}}public void cancel() {try {this.status = status.cancel();System.out.println("订单 " + orderId + " 已取消");} catch (IllegalStateException e) {System.out.println("取消失败: " + e.getMessage());}}// Getterpublic OrderStatus getStatus() {return status;}
}class StateMachineDemo {public static void main(String[] args) {Order order = new Order("ORDER_001");// 正常流程order.proceedToNext(); // CREATED -> PAIDorder.proceedToNext(); // PAID -> SHIPPED// 尝试取消(应该失败)order.cancel();order.proceedToNext(); // SHIPPED -> DELIVEREDorder.proceedToNext(); // DELIVERED -> COMPLETED// 尝试继续转换(应该失败)order.proceedToNext();}
}

复杂示例:权限系统设计

import java.util.EnumSet;
import java.util.Set;public enum Permission {// 权限定义READ(1, "读取权限"),WRITE(2, "写入权限"),EXECUTE(4, "执行权限"),DELETE(8, "删除权限"),CREATE(16, "创建权限"),ADMIN(32, "管理员权限"),AUDIT(64, "审计权限"),BACKUP(128, "备份权限");private final int value;private final String description;Permission(int value, String description) {this.value = value;this.description = description;}public int getValue() {return value;}public String getDescription() {return description;}// 权限组合操作public static Set<Permission> fromInt(int permissionValue) {Set<Permission> permissions = EnumSet.noneOf(Permission.class);for (Permission permission : values()) {if ((permissionValue & permission.value) != 0) {permissions.add(permission);}}return permissions;}public static int toInt(Set<Permission> permissions) {int value = 0;for (Permission permission : permissions) {value |= permission.value;}return value;}public static boolean hasPermission(int permissionValue, Permission required) {return (permissionValue & required.value) != 0;}public static int addPermission(int permissionValue, Permission permission) {return permissionValue | permission.value;}public static int removePermission(int permissionValue, Permission permission) {return permissionValue & ~permission.value;}// 预定义的权限组合public static final int BASIC_ACCESS = toInt(EnumSet.of(READ, WRITE));public static final int FULL_ACCESS = toInt(EnumSet.of(READ, WRITE, EXECUTE, DELETE, CREATE));public static final int ADMIN_ACCESS = toInt(EnumSet.allOf(Permission.class));
}// 用户权限管理
class User {private String username;private int permissions;public User(String username, int permissions) {this.username = username;this.permissions = permissions;}public boolean hasPermission(Permission permission) {return Permission.hasPermission(permissions, permission);}public void grantPermission(Permission permission) {permissions = Permission.addPermission(permissions, permission);System.out.println("授予 " + username + " 权限: " + permission.getDescription());}public void revokePermission(Permission permission) {permissions = Permission.removePermission(permissions, permission);System.out.println("撤销 " + username + " 权限: " + permission.getDescription());}public void printPermissions() {Set<Permission> userPermissions = Permission.fromInt(permissions);System.out.println(username + " 的权限:");for (Permission perm : userPermissions) {System.out.println("  - " + perm.getDescription());}}
}class PermissionSystemDemo {public static void main(String[] args) {// 创建用户User user = new User("张三", Permission.BASIC_ACCESS);user.printPermissions();// 授予额外权限user.grantPermission(Permission.DELETE);user.grantPermission(Permission.EXECUTE);user.printPermissions();// 检查权限System.out.println("是否有读取权限: " + user.hasPermission(Permission.READ));System.out.println("是否有管理员权限: " + user.hasPermission(Permission.ADMIN));// 撤销权限user.revokePermission(Permission.DELETE);user.printPermissions();// 使用预定义权限组合User admin = new User("管理员", Permission.ADMIN_ACCESS);admin.printPermissions();}
}

设计原则

// 1. 使用枚举代替常量
public class GoodDesign {// 好的设计:使用枚举public enum LogLevel {DEBUG, INFO, WARN, ERROR}public void log(LogLevel level, String message) {// 实现日志记录}
}// 2. 枚举应该是不可变的
public enum ImmutableEnum {VALUE1("data1"),VALUE2("data2");private final String data; // 使用final确保不可变ImmutableEnum(String data) {this.data = data;}public String getData() {return data;}
}// 3. 合理使用枚举方法
public enum SmartEnum {FIRST,SECOND,THIRD;// 提供有用的方法public boolean isFirst() {return this == FIRST;}public boolean isLast() {return this == THIRD;}public SmartEnum getNext() {if (this == THIRD) return FIRST;return values()[ordinal() + 1];}
}// 4. 避免在枚举中保存大量数据
public enum LightweightEnum {OPTION_A,OPTION_B,OPTION_C;// 避免这样设计// private byte[] largeData = new byte[1024 * 1024]; // 1MB数据
}

总结

Java枚举的核心要点:

  1. 定义:使用enum关键字,隐含继承java.lang.Enum
  2. 常量:枚举常量是类的实例,在类加载时创建
  3. 构造方法:必须是private,在常量声明时调用
  4. 方法:可以有实例方法、静态方法、抽象方法
  5. 接口:枚举可以实现接口
  6. 内置方法values(), valueOf(), name(), ordinal()
  7. 集合支持EnumSetEnumMap提供高性能操作
  8. 设计模式:完美实现单例模式、策略模式、状态机等
  9. 线程安全:枚举实例创建是线程安全的

注解 (Annotation)

注解的定义和基本概念

注解定义语法

[访问修饰符] @interface 注解名 {// 注解元素(方法)// 默认值
}

基本注解示例

// 最简单的注解
public @interface MyAnnotation {
}// 使用注解
@MyAnnotation
class MyClass {@MyAnnotationpublic void myMethod() {}
}

注解元素(方法)

import java.lang.annotation.*;// 定义包含各种类型元素的注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface ComplexAnnotation {// 基本类型int id() default 0;String name() default "";double version() default 1.0;boolean enabled() default true;// 数组类型String[] tags() default {};int[] values() default {};// 枚举类型Status status() default Status.ACTIVE;// Class类型Class<?> processor() default Void.class;// 注解类型SubAnnotation subAnnotation() default @SubAnnotation;// 特殊值 - 不需要默认值String value() default "";
}// 嵌套的注解
@interface SubAnnotation {String info() default "sub";
}// 枚举用于注解
enum Status {ACTIVE, INACTIVE, PENDING
}// 使用复杂注解
@ComplexAnnotation(id = 1,name = "测试类",version = 2.0,tags = {"java", "annotation"},values = {1, 2, 3},status = Status.ACTIVE,processor = String.class,subAnnotation = @SubAnnotation(info = "自定义信息"),value = "主要值"
)
class AnnotatedClass {@ComplexAnnotation(name = "字段注解", enabled = false)private String data;@ComplexAnnotation(id = 100, value = "方法注解")public void process() {}
}

元注解(Meta-Annotations)

import java.lang.annotation.*;// @Target - 指定注解可以应用的位置
@Target({ElementType.TYPE,           // 类、接口、枚举ElementType.FIELD,          // 字段ElementType.METHOD,         // 方法ElementType.PARAMETER,      // 参数ElementType.CONSTRUCTOR,    // 构造方法ElementType.LOCAL_VARIABLE, // 局部变量ElementType.ANNOTATION_TYPE,// 注解ElementType.PACKAGE,        // 包ElementType.TYPE_PARAMETER, // 类型参数(Java 8+)ElementType.TYPE_USE        // 类型使用(Java 8+)
})
// @Retention - 指定注解保留策略
@Retention(RetentionPolicy.RUNTIME) // 运行时保留
// @Retention(RetentionPolicy.SOURCE)  // 仅源码阶段
// @Retention(RetentionPolicy.CLASS)   // 编译阶段// @Documented - 包含在Javadoc中
@Documented// @Inherited - 允许子类继承
@Inherited// @Repeatable - 可重复注解(Java 8+)
@Repeatable(Roles.class)
public @interface Role {String value();
}// 容器注解
@interface Roles {Role[] value();
}// 使用示例
@Role("管理员")
@Role("开发者")  // 可重复注解
class User {
}

内置的标准注解

import java.util.*;// 使用内置注解的示例
@SuppressWarnings({"unchecked", "deprecation"})
public class BuiltInAnnotations {// @Override - 表示方法重写@Overridepublic String toString() {return "BuiltInAnnotations实例";}// @Deprecated - 标记已过时@Deprecated(since = "2.0", forRemoval = true)public void oldMethod() {System.out.println("这是过时的方法");}// @SuppressWarnings - 抑制警告@SuppressWarnings("rawtypes")public void processList(List list) {// 不使用泛型的代码}// @SafeVarargs - 表示方法不会对可变参数进行危险操作@SafeVarargspublic final <T> void safeMethod(T... args) {for (T arg : args) {System.out.println(arg);}}// @FunctionalInterface - 函数式接口@FunctionalInterfaceinterface MyFunction {void apply(String input);// 只能有一个抽象方法// void anotherMethod(); // 编译错误}public void useNewMethod() {System.out.println("使用新方法");}public static void main(String[] args) {BuiltInAnnotations example = new BuiltInAnnotations();example.oldMethod(); // 编译器会显示过时警告}
}

注解的三种保留策略

// SOURCE级别注解 - 仅在源码中保留
@Retention(RetentionPolicy.SOURCE)
@interface SourceAnnotation {String value();
}// CLASS级别注解 - 编译到class文件,但运行时不可见
@Retention(RetentionPolicy.CLASS)
@interface ClassAnnotation {String value();
}// RUNTIME级别注解 - 运行时可通过反射获取
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeAnnotation {String value();
}// 使用不同保留策略的注解
@SourceAnnotation("源码注解")
@ClassAnnotation("类文件注解")
@RuntimeAnnotation("运行时注解")
public class RetentionExample {@SourceAnnotation("方法源码注解")public void method() {}
}

运行时注解处理(反射)

import java.lang.reflect.*;// 自定义运行时注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@interface MyRuntimeAnnotation {String name() default "";int priority() default 0;String[] tags() default {};
}// 使用注解的类
@MyRuntimeAnnotation(name = "用户服务", priority = 1, tags = {"service", "user"})
class UserService {@MyRuntimeAnnotation(name = "用户ID")private Long userId;@MyRuntimeAnnotation(name = "获取用户", priority = 2)public void getUser() {System.out.println("获取用户信息");}@MyRuntimeAnnotationpublic void defaultMethod() {}
}// 注解处理器
class AnnotationProcessor {public static void processAnnotations(Class<?> clazz) {System.out.println("处理类: " + clazz.getName());// 处理类级别的注解if (clazz.isAnnotationPresent(MyRuntimeAnnotation.class)) {MyRuntimeAnnotation annotation = clazz.getAnnotation(MyRuntimeAnnotation.class);System.out.println("类注解 - 名称: " + annotation.name() + ", 优先级: " + annotation.priority() +", 标签: " + String.join(", ", annotation.tags()));}// 处理字段级别的注解for (Field field : clazz.getDeclaredFields()) {if (field.isAnnotationPresent(MyRuntimeAnnotation.class)) {MyRuntimeAnnotation annotation = field.getAnnotation(MyRuntimeAnnotation.class);System.out.println("字段注解 - 字段: " + field.getName() + ", 名称: " + annotation.name());}}// 处理方法级别的注解for (Method method : clazz.getDeclaredMethods()) {if (method.isAnnotationPresent(MyRuntimeAnnotation.class)) {MyRuntimeAnnotation annotation = method.getAnnotation(MyRuntimeAnnotation.class);System.out.println("方法注解 - 方法: " + method.getName() + ", 名称: " + annotation.name() +", 优先级: " + annotation.priority());}}}public static void main(String[] args) {processAnnotations(UserService.class);}
}

编译时注解处理器(自定义注解处理器)

import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.tools.*;
import java.util.*;
import java.io.*;// 编译时注解
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
@interface GenerateBuilder {String className() default "";
}// 使用注解
@GenerateBuilder(className = "UserBuilder")
class User {private String name;private int age;// getters and setterspublic String getName() { return name; }public void setName(String name) { this.name = name; }public int getAge() { return age; }public void setAge(int age) { this.age = age; }
}// 注解处理器(需要配置到META-INF/services/javax.annotation.processing.Processor)
@SupportedAnnotationTypes("GenerateBuilder")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class BuilderProcessor extends AbstractProcessor {@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {for (TypeElement annotation : annotations) {Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);for (Element element : annotatedElements) {if (element.getKind() == ElementKind.CLASS) {generateBuilder((TypeElement) element);}}}return true;}private void generateBuilder(TypeElement classElement) {GenerateBuilder annotation = classElement.getAnnotation(GenerateBuilder.class);String className = annotation.className();String originalClassName = classElement.getSimpleName().toString();if (className.isEmpty()) {className = originalClassName + "Builder";}StringBuilder builder = new StringBuilder();builder.append("public class ").append(className).append(" {\n");builder.append("    private ").append(originalClassName).append(" instance = new ").append(originalClassName).append("();\n\n");// 为每个字段生成setter方法for (Element enclosed : classElement.getEnclosedElements()) {if (enclosed.getKind() == ElementKind.FIELD) {String fieldName = enclosed.getSimpleName().toString();String fieldType = enclosed.asType().toString();builder.append("    public ").append(className).append(" set").append(capitalize(fieldName)).append("(").append(fieldType).append(" ").append(fieldName).append(") {\n").append("        instance.set").append(capitalize(fieldName)).append("(").append(fieldName).append(");\n").append("        return this;\n").append("    }\n\n");}}builder.append("    public ").append(originalClassName).append(" build() {\n").append("        return instance;\n").append("    }\n").append("}\n");// 写入文件try {JavaFileObject builderFile = processingEnv.getFiler().createSourceFile(className);try (PrintWriter out = new PrintWriter(builderFile.openWriter())) {out.println(builder.toString());}} catch (IOException e) {e.printStackTrace();}}private String capitalize(String str) {return str.substring(0, 1).toUpperCase() + str.substring(1);}
}

自定义验证注解(参数验证注解)

import javax.validation.*;
import java.lang.annotation.*;
import java.util.regex.Pattern;// 自定义验证注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EmailValidator.class)
@interface ValidEmail {String message() default "无效的邮箱地址";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}// 验证器实现
class EmailValidator implements ConstraintValidator<ValidEmail, String> {private static final String EMAIL_PATTERN = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";@Overridepublic void initialize(ValidEmail constraintAnnotation) {}@Overridepublic boolean isValid(String email, ConstraintValidatorContext context) {if (email == null) {return false;}return Pattern.matches(EMAIL_PATTERN, email);}
}// 范围验证注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = RangeValidator.class)
@interface ValidRange {int min() default 0;int max() default Integer.MAX_VALUE;String message() default "数值超出范围";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}class RangeValidator implements ConstraintValidator<ValidRange, Integer> {private int min;private int max;@Overridepublic void initialize(ValidRange constraintAnnotation) {this.min = constraintAnnotation.min();this.max = constraintAnnotation.max();}@Overridepublic boolean isValid(Integer value, ConstraintValidatorContext context) {if (value == null) {return false;}return value >= min && value <= max;}
}// 使用验证注解的类
class User {@ValidEmailprivate String email;@ValidRange(min = 1, max = 120)private Integer age;// 构造方法、getter、setterpublic User(String email, Integer age) {this.email = email;this.age = age;}public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }
}// 验证工具类
class ValidationUtil {public static void validate(Object obj) {// 简化版的验证逻辑// 实际中可以使用Hibernate Validator等框架System.out.println("验证对象: " + obj.getClass().getSimpleName());}public static void main(String[] args) {User user1 = new User("valid@example.com", 25);User user2 = new User("invalid-email", 150);validate(user1);validate(user2);}
}

Spring风格的注解(模仿Spring框架的注解)

import java.lang.annotation.*;// 组件注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
@interface Service {String value() default "";
}@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
@interface Repository {String value() default "";
}@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
@interface Controller {String value() default "";
}// 元注解
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Component {String value() default "";
}// 自动注入注解
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Autowired {boolean required() default true;
}// 配置注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Configuration {
}@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Bean {String name() default "";boolean autowire() default true;
}// 请求映射注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface RequestMapping {String value() default "";RequestMethod method() default RequestMethod.GET;
}enum RequestMethod {GET, POST, PUT, DELETE, PATCH
}// 使用Spring风格注解的示例
@Configuration
class AppConfig {@Bean(name = "userService")public UserService userService() {return new UserService();}
}@Service("userService")
class UserService {public String getUserInfo() {return "用户信息";}
}@Controller
@RequestMapping("/user")
class UserController {@Autowiredprivate UserService userService;@RequestMapping(value = "/info", method = RequestMethod.GET)public String getUserInfo() {return userService.getUserInfo();}
}@Repository
class UserRepository {public String findUser() {return "从数据库查询用户";}
}

测试框架注解(模仿JUnit的测试注解)

import java.lang.annotation.*;
import java.lang.reflect.*;// 测试框架注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Test {Class<? extends Throwable> expected() default None.class;long timeout() default 0L;class None extends Throwable {private None() {}}
}@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Before {
}@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface After {
}@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface BeforeClass {
}@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface AfterClass {
}@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Ignore {String value() default "";
}// 简单的测试运行器
class SimpleTestRunner {public static void runTests(Class<?> testClass) throws Exception {System.out.println("运行测试类: " + testClass.getSimpleName());Object testInstance = testClass.getDeclaredConstructor().newInstance();// 执行 @BeforeClass 方法for (Method method : testClass.getDeclaredMethods()) {if (method.isAnnotationPresent(BeforeClass.class)) {method.invoke(null);}}// 执行测试方法for (Method method : testClass.getDeclaredMethods()) {if (method.isAnnotationPresent(Test.class)) {if (method.isAnnotationPresent(Ignore.class)) {Ignore ignore = method.getAnnotation(Ignore.class);System.out.println("忽略测试: " + method.getName() + " - " + ignore.value());continue;}Test testAnnotation = method.getAnnotation(Test.class);// 执行 @Before 方法for (Method beforeMethod : testClass.getDeclaredMethods()) {if (beforeMethod.isAnnotationPresent(Before.class)) {beforeMethod.invoke(testInstance);}}System.out.print("执行测试: " + method.getName());long startTime = System.currentTimeMillis();try {method.invoke(testInstance);// 检查是否期望异常if (testAnnotation.expected() != Test.None.class) {System.out.println(" - 失败: 期望异常 " + testAnnotation.expected().getSimpleName());} else {System.out.println(" - 通过");}} catch (InvocationTargetException e) {Throwable cause = e.getCause();if (testAnnotation.expected().isInstance(cause)) {System.out.println(" - 通过 (抛出预期异常)");} else {System.out.println(" - 失败: " + cause.getMessage());}}// 检查超时long duration = System.currentTimeMillis() - startTime;if (testAnnotation.timeout() > 0 && duration > testAnnotation.timeout()) {System.out.println(" - 失败: 超时 " + duration + "ms");}// 执行 @After 方法for (Method afterMethod : testClass.getDeclaredMethods()) {if (afterMethod.isAnnotationPresent(After.class)) {afterMethod.invoke(testInstance);}}}}// 执行 @AfterClass 方法for (Method method : testClass.getDeclaredMethods()) {if (method.isAnnotationPresent(AfterClass.class)) {method.invoke(null);}}}
}// 测试类示例
class CalculatorTest {private Calculator calculator;@BeforeClasspublic static void setUpClass() {System.out.println("测试类初始化");}@Beforepublic void setUp() {calculator = new Calculator();System.out.println("测试前准备");}@Testpublic void testAddition() {int result = calculator.add(2, 3);assert result == 5 : "加法测试失败";}@Test(expected = ArithmeticException.class)public void testDivisionByZero() {calculator.divide(10, 0);}@Test(timeout = 1000L)public void testTimeout() {// 模拟耗时操作try {Thread.sleep(500);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}@Ignore("暂时跳过")@Testpublic void testIgnored() {System.out.println("这个测试被跳过了");}@Afterpublic void tearDown() {calculator = null;System.out.println("测试后清理");}@AfterClasspublic static void tearDownClass() {System.out.println("测试类清理");}
}class Calculator {public int add(int a, int b) {return a + b;}public int divide(int a, int b) {if (b == 0) {throw new ArithmeticException("除数不能为零");}return a / b;}
}

复杂示例:模仿Hibernate的ORM注解

import java.lang.annotation.*;
import java.util.*;// ORM注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Entity
@interface Table {String name() default "";
}@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface Column {String name() default "";boolean nullable() default true;int length() default 255;boolean unique() default false;
}@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Id {String generator() default "auto";
}@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface GeneratedValue {GenerationType strategy() default GenerationType.AUTO;
}enum GenerationType {AUTO, IDENTITY, SEQUENCE, TABLE
}@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface OneToMany {String mappedBy() default "";CascadeType[] cascade() default {};FetchType fetch() default FetchType.LAZY;
}@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface ManyToOne {CascadeType[] cascade() default {};FetchType fetch() default FetchType.EAGER;boolean optional() default true;
}enum CascadeType {ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH
}enum FetchType {LAZY, EAGER
}@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Entity {
}// 使用ORM注解的实体类
@Table(name = "users")
class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "username", nullable = false, unique = true, length = 50)private String username;@Column(name = "email", nullable = false)private String email;@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)private List<Order> orders = new ArrayList<>();// 构造方法、getter、setterpublic User() {}public User(String username, String email) {this.username = username;this.email = email;}// getter和setterpublic Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public List<Order> getOrders() { return orders; }public void setOrders(List<Order> orders) { this.orders = orders; }
}@Table(name = "orders")
class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(name = "order_number", nullable = false, unique = true)private String orderNumber;@Column(name = "total_amount")private Double totalAmount;@ManyToOne(fetch = FetchType.EAGER)private User user;// 构造方法、getter、setterpublic Order() {}public Order(String orderNumber, Double totalAmount, User user) {this.orderNumber = orderNumber;this.totalAmount = totalAmount;this.user = user;}public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getOrderNumber() { return orderNumber; }public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; }public Double getTotalAmount() { return totalAmount; }public void setTotalAmount(Double totalAmount) { this.totalAmount = totalAmount; }public User getUser() { return user; }public void setUser(User user) { this.user = user; }
}// 简单的ORM处理器
class SimpleORM {public static String generateCreateTableSQL(Class<?> entityClass) {if (!entityClass.isAnnotationPresent(Table.class)) {throw new IllegalArgumentException("类 " + entityClass.getName() + " 不是实体类");}Table table = entityClass.getAnnotation(Table.class);String tableName = table.name().isEmpty() ? entityClass.getSimpleName().toLowerCase() : table.name();StringBuilder sql = new StringBuilder();sql.append("CREATE TABLE ").append(tableName).append(" (\n");List<String> columns = new ArrayList<>();List<String> constraints = new ArrayList<>();for (java.lang.reflect.Field field : entityClass.getDeclaredFields()) {if (field.isAnnotationPresent(Column.class)) {Column column = field.getAnnotation(Column.class);String columnName = column.name().isEmpty() ? field.getName() : column.name();String columnType = getSQLType(field.getType());StringBuilder columnDef = new StringBuilder();columnDef.append("    ").append(columnName).append(" ").append(columnType);if (!column.nullable()) {columnDef.append(" NOT NULL");}if (column.unique()) {constraints.add("    UNIQUE (" + columnName + ")");}if (field.isAnnotationPresent(Id.class)) {columnDef.append(" PRIMARY KEY");}columns.add(columnDef.toString());}}sql.append(String.join(",\n", columns));if (!constraints.isEmpty()) {sql.append(",\n").append(String.join(",\n", constraints));}sql.append("\n);");return sql.toString();}private static String getSQLType(Class<?> type) {if (type == Long.class || type == long.class) return "BIGINT";if (type == Integer.class || type == int.class) return "INT";if (type == String.class) return "VARCHAR(255)";if (type == Double.class || type == double.class) return "DECIMAL(10,2)";if (type == Boolean.class || type == boolean.class) return "BOOLEAN";if (type == Date.class) return "DATETIME";return "TEXT";}public static void main(String[] args) {System.out.println("User表SQL:");System.out.println(generateCreateTableSQL(User.class));System.out.println("\nOrder表SQL:");System.out.println(generateCreateTableSQL(Order.class));}
}

设计原则

// 1. 注解应该简单明了
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface SimpleAnnotation {String value(); // 使用value作为主要元素
}// 2. 提供合理的默认值
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface GoodDesign {String name() default "";int retries() default 3;boolean async() default false;
}// 3. 使用枚举提高类型安全
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface StatusField {Status status() default Status.ACTIVE;
}enum Status {ACTIVE, INACTIVE, PENDING, DELETED
}// 4. 避免注解过度复杂
// 不好的设计:注解包含太多复杂逻辑
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface OverComplex {Class<?>[] types();String[] names();int[] values();boolean[] flags();
}// 好的设计:拆分多个简单注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Cache {String key();long ttl() default 3600;
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Retry {int attempts() default 3;long delay() default 1000;
}// 5. 文档化注解的使用
/*** 用于标记需要权限验证的方法* * 示例:* {@code* @RequiresPermission("user:read")* public void getUser() { ... }* }*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresPermission {String value();String description() default "";
}

总结

Java注解的核心要点:

  1. 定义:使用@interface关键字,本质是接口
  2. 元素:可以定义各种类型的元素(方法),支持默认值
  3. 元注解@Target, @Retention, @Documented, @Inherited, @Repeatable
  4. 保留策略SOURCE, CLASS, RUNTIME
  5. 处理方式:编译时处理(注解处理器)或运行时处理(反射)
  6. 内置注解@Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface
  7. 应用场景:配置、验证、代码生成、框架集成等

记录 (Record)

记录类的定义和基本概念

记录类定义语法

[访问修饰符] record 记录名(参数列表) [implements 接口1, 接口2, ...] {// 紧凑构造方法// 实例方法// 静态方法// 静态字段// 嵌套类型
}

基本记录类示例

// 最简单的记录类
public record Point(int x, int y) {
}// 使用记录类
class RecordDemo {public static void main(String[] args) {Point p1 = new Point(10, 20);Point p2 = new Point(10, 20);System.out.println(p1);         // 自动生成toString: Point[x=10, y=20]System.out.println(p1.x());     // 自动生成的访问器方法System.out.println(p1.y());System.out.println(p1.equals(p2)); // 自动生成equals: trueSystem.out.println(p1.hashCode() == p2.hashCode()); // 自动生成hashCode: true}
}

记录类的组件(自动生成的成员)

// 记录类自动生成以下成员:
public record Person(String name, int age, String email) {// 自动生成:// 1. private final 字段:name, age, email// 2. 规范构造方法:Person(String name, int age, String email)// 3. 访问器方法:name(), age(), email()// 4. equals() 方法// 5. hashCode() 方法// 6. toString() 方法
}// 手动实现等效的普通类
class TraditionalPerson {private final String name;private final int age;private final String email;public TraditionalPerson(String name, int age, String email) {this.name = name;this.age = age;this.email = email;}public String name() { return name; }public int age() { return age; }public String email() { return email; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (!(o instanceof TraditionalPerson)) return false;TraditionalPerson that = (TraditionalPerson) o;return age == that.age && Objects.equals(name, that.name) && Objects.equals(email, that.email);}@Overridepublic int hashCode() {return Objects.hash(name, age, email);}@Overridepublic String toString() {return "TraditionalPerson[name=" + name + ", age=" + age + ", email=" + email + "]";}
}

记录类的构造方法

紧凑构造方法

public record User(String username, String email, int age) {// 紧凑构造方法 - 用于参数验证和规范化public User {// 参数验证if (username == null || username.trim().isEmpty()) {throw new IllegalArgumentException("用户名不能为空");}if (age < 0 || age > 150) {throw new IllegalArgumentException("年龄必须在0-150之间");}if (email == null || !email.contains("@")) {throw new IllegalArgumentException("邮箱格式不正确");}// 规范化username = username.trim();email = email.toLowerCase();// 不需要显式赋值,编译器会自动处理}
}// 使用验证
class ConstructorDemo {public static void main(String[] args) {try {User user1 = new User("  John  ", "JOHN@EXAMPLE.COM", 25);System.out.println(user1); // User[username=John, email=john@example.com, age=25]User user2 = new User("", "invalid", 200); // 抛出异常} catch (IllegalArgumentException e) {System.out.println("创建用户失败: " + e.getMessage());}}
}

自定义构造方法

public record Employee(String id, String name, String department, double salary) {// 自定义构造方法 - 必须调用主构造方法public Employee(String name, String department) {this(generateId(), name, department, 0.0);}public Employee(String name) {this(generateId(), name, "未分配", 0.0);}// 静态方法生成IDprivate static String generateId() {return "EMP_" + System.currentTimeMillis() + "_" + (int)(Math.random() * 1000);}// 工厂方法public static Employee createManager(String name) {return new Employee(generateId(), name, "管理部", 10000.0);}// 紧凑构造方法public Employee {if (name == null || name.trim().isEmpty()) {throw new IllegalArgumentException("员工姓名不能为空");}if (salary < 0) {throw new IllegalArgumentException("薪资不能为负数");}name = name.trim();}
}class CustomConstructorDemo {public static void main(String[] args) {Employee emp1 = new Employee("E001", "张三", "技术部", 8000.0);Employee emp2 = new Employee("李四", "市场部"); // 使用自定义构造方法Employee emp3 = new Employee("王五"); // 使用另一个自定义构造方法Employee manager = Employee.createManager("赵六"); // 工厂方法System.out.println(emp1);System.out.println(emp2);System.out.println(emp3);System.out.println(manager);}
}

记录类的实例方法和静态方法

import java.time.LocalDate;
import java.time.Period;public record Person(String name, LocalDate birthDate, String email) {// 实例方法public int getAge() {return Period.between(birthDate, LocalDate.now()).getYears();}public boolean isAdult() {return getAge() >= 18;}public String getInitials() {String[] names = name.split(" ");if (names.length == 1) {return name.substring(0, 1).toUpperCase();}return (names[0].substring(0, 1) + names[names.length - 1].substring(0, 1)).toUpperCase();}// 静态方法public static Person create(String name, int birthYear, int birthMonth, int birthDay, String email) {LocalDate birthDate = LocalDate.of(birthYear, birthMonth, birthDay);return new Person(name, birthDate, email);}public static boolean isValidEmail(String email) {return email != null && email.contains("@") && email.contains(".");}// 重写访问器方法@Overridepublic String name() {// 返回格式化的姓名return name.toUpperCase();}// 紧凑构造方法public Person {if (birthDate != null && birthDate.isAfter(LocalDate.now())) {throw new IllegalArgumentException("出生日期不能在未来");}if (!isValidEmail(email)) {throw new IllegalArgumentException("邮箱格式不正确");}}
}class MethodDemo {public static void main(String[] args) {Person person = Person.create("张三", 1990, 5, 15, "zhangsan@example.com");System.out.println("姓名: " + person.name());System.out.println("年龄: " + person.getAge());System.out.println("是否成年: " + person.isAdult());System.out.println("姓名缩写: " + person.getInitials());System.out.println("完整信息: " + person);}
}

记录类的静态字段(静态字段和常量)

public record BankAccount(String accountNumber, String accountHolder, double balance) {// 静态字段private static final String BANK_NAME = "Java银行";private static final double MIN_BALANCE = 0.0;private static final double MAX_BALANCE = 1_000_000.0;private static int accountCount = 0;// 静态初始化块static {System.out.println("银行账户系统初始化");}// 紧凑构造方法public BankAccount {if (balance < MIN_BALANCE) {throw new IllegalArgumentException("余额不能为负数");}if (balance > MAX_BALANCE) {throw new IllegalArgumentException("余额超过上限");}if (accountNumber == null || accountNumber.length() != 16) {throw new IllegalArgumentException("账号必须是16位");}accountCount++;}// 实例方法public BankAccount deposit(double amount) {if (amount <= 0) {throw new IllegalArgumentException("存款金额必须为正数");}return new BankAccount(accountNumber, accountHolder, balance + amount);}public BankAccount withdraw(double amount) {if (amount <= 0) {throw new IllegalArgumentException("取款金额必须为正数");}if (balance - amount < MIN_BALANCE) {throw new IllegalArgumentException("余额不足");}return new BankAccount(accountNumber, accountHolder, balance - amount);}// 静态方法public static String getBankName() {return BANK_NAME;}public static int getAccountCount() {return accountCount;}public static BankAccount createAccount(String accountHolder, double initialBalance) {String accountNumber = generateAccountNumber();return new BankAccount(accountNumber, accountHolder, initialBalance);}private static String generateAccountNumber() {return "62" + System.currentTimeMillis() % 10_000_000_000L;}// 重写toString以包含静态信息@Overridepublic String toString() {return String.format("BankAccount[银行=%s, 账号=%s, 户主=%s, 余额=%.2f]",BANK_NAME, accountNumber, accountHolder, balance);}
}class StaticFieldDemo {public static void main(String[] args) {System.out.println("银行名称: " + BankAccount.getBankName());BankAccount account1 = BankAccount.createAccount("张三", 1000.0);BankAccount account2 = BankAccount.createAccount("李四", 500.0);System.out.println(account1);System.out.println(account2);// 存款取款操作(返回新对象)BankAccount updatedAccount = account1.deposit(500.0).withdraw(200.0);System.out.println("更新后: " + updatedAccount);System.out.println("总账户数: " + BankAccount.getAccountCount());}
}

记录类实现接口

// 定义接口
interface Identifiable {String getId();boolean isValid();
}interface Auditable {void audit();default String getAuditInfo() {return "审计信息";}
}interface JsonSerializable {String toJson();
}// 记录类实现多个接口
public record Product(String id, String name, double price, int stock) implements Identifiable, Auditable, JsonSerializable {// 实现Identifiable接口@Overridepublic String getId() {return id;}@Overridepublic boolean isValid() {return id != null && !id.trim().isEmpty() &&name != null && !name.trim().isEmpty() &&price >= 0 && stock >= 0;}// 实现Auditable接口@Overridepublic void audit() {System.out.printf("产品审计: %s (ID: %s, 价格: %.2f, 库存: %d)%n",name, id, price, stock);}// 实现JsonSerializable接口@Overridepublic String toJson() {return String.format("""{"id": "%s","name": "%s","price": %.2f,"stock": %d}""", id, name, price, stock);}// 实例方法public Product applyDiscount(double discountRate) {if (discountRate < 0 || discountRate > 1) {throw new IllegalArgumentException("折扣率必须在0-1之间");}return new Product(id, name, price * (1 - discountRate), stock);}public boolean isInStock() {return stock > 0;}// 紧凑构造方法public Product {if (id == null || id.trim().isEmpty()) {id = generateId();}if (price < 0) {throw new IllegalArgumentException("价格不能为负数");}if (stock < 0) {throw new IllegalArgumentException("库存不能为负数");}name = name != null ? name.trim() : "未命名产品";}private static String generateId() {return "PROD_" + System.nanoTime();}
}class InterfaceDemo {public static void main(String[] args) {Product product = new Product(null, "笔记本电脑", 5999.0, 10);// 作为Identifiable使用Identifiable identifiable = product;System.out.println("ID: " + identifiable.getId());System.out.println("是否有效: " + identifiable.isValid());// 作为Auditable使用Auditable auditable = product;auditable.audit();System.out.println("审计信息: " + auditable.getAuditInfo());// 作为JsonSerializable使用JsonSerializable serializable = product;System.out.println("JSON: " + serializable.toJson());// 使用记录类方法Product discounted = product.applyDiscount(0.1);System.out.println("打折后: " + discounted);System.out.println("是否有库存: " + discounted.isInStock());}
}

嵌套记录类(内部记录类和静态嵌套记录类)

import java.util.*;// 外部类
public class University {private final String name;private final List<Department> departments;public University(String name) {this.name = name;this.departments = new ArrayList<>();}// 静态嵌套记录类public record Department(String code, String name, String dean) {// 紧凑构造方法public Department {if (code == null || code.length() != 4) {throw new IllegalArgumentException("院系代码必须是4位");}code = code.toUpperCase();name = name != null ? name.trim() : "";}// 实例方法public String getFullName() {return code + " - " + name;}public static Department create(String code, String name, String dean) {return new Department(code, name, dean);}}// 内部记录类(非静态)public record Course(Department department, String courseCode, String courseName, int credits) {// 内部记录类可以访问外部类的实例成员public String getUniversityInfo() {return "课程属于: " + University.this.name;}public String getFullCourseCode() {return department.code() + "-" + courseCode;}}// 外部类方法public void addDepartment(String code, String name, String dean) {Department dept = new Department(code, name, dean);departments.add(dept);}public List<Department> getDepartments() {return Collections.unmodifiableList(departments);}public Course createCourse(String deptCode, String courseCode, String courseName, int credits) {Department dept = departments.stream().filter(d -> d.code().equals(deptCode)).findFirst().orElseThrow(() -> new IllegalArgumentException("院系不存在: " + deptCode));return new Course(dept, courseCode, courseName, credits);}
}class NestedRecordDemo {public static void main(String[] args) {University university = new University("Java大学");// 使用静态嵌套记录类University.Department csDept = new University.Department("CS01", "计算机科学", "张教授");University.Department mathDept = University.Department.create("MATH", "数学系", "李教授");university.addDepartment("CS01", "计算机科学", "张教授");university.addDepartment("MATH", "数学系", "李教授");System.out.println("院系: " + csDept.getFullName());System.out.println("院系: " + mathDept);// 使用内部记录类University.Course course = university.createCourse("CS01", "CS101", "Java编程", 3);System.out.println("课程: " + course.getFullCourseCode());System.out.println("课程信息: " + course.getUniversityInfo());// 遍历院系System.out.println("\n所有院系:");for (University.Department dept : university.getDepartments()) {System.out.println(" - " + dept.getFullName() + ", 院长: " + dept.dean());}}
}

泛型记录类(带泛型参数的记录类)

import java.util.*;
import java.util.function.*;// 泛型记录类
public record Pair<T, U>(T first, U second) {// 实例方法public <V> Pair<V, U> mapFirst(Function<? super T, ? extends V> mapper) {return new Pair<>(mapper.apply(first), second);}public <V> Pair<T, V> mapSecond(Function<? super U, ? extends V> mapper) {return new Pair<>(first, mapper.apply(second));}public Pair<U, T> swap() {return new Pair<>(second, first);}public void forEach(BiConsumer<? super T, ? super U> action) {action.accept(first, second);}// 静态工厂方法public static <T, U> Pair<T, U> of(T first, U second) {return new Pair<>(first, second);}public static <T> Pair<T, T> duplicate(T value) {return new Pair<>(value, value);}// 重写toString@Overridepublic String toString() {return "(" + first + ", " + second + ")";}
}// 另一个泛型记录类示例
public record Result<T, E>(T value, E error, boolean success) {// 紧凑构造方法public Result {if (success && error != null) {throw new IllegalArgumentException("成功结果不能有错误信息");}if (!success && value != null) {throw new IllegalArgumentException("失败结果不能有值");}}// 成功工厂方法public static <T, E> Result<T, E> success(T value) {return new Result<>(value, null, true);}// 失败工厂方法public static <T, E> Result<T, E> failure(E error) {return new Result<>(null, error, false);}// 实例方法public T getOrElse(T defaultValue) {return success ? value : defaultValue;}public Result<T, E> map(Function<? super T, ? extends T> mapper) {if (!success) return this;return Result.success(mapper.apply(value));}public <U> Result<U, E> flatMap(Function<? super T, Result<U, E>> mapper) {if (!success) return Result.failure(error);return mapper.apply(value);}public void ifSuccess(Consumer<? super T> action) {if (success) {action.accept(value);}}public void ifFailure(Consumer<? super E> action) {if (!success) {action.accept(error);}}
}class GenericRecordDemo {public static void main(String[] args) {// 使用Pair记录类Pair<String, Integer> nameAge = new Pair<>("张三", 25);Pair<String, String> nameUpperCase = nameAge.mapFirst(String::toUpperCase);Pair<Integer, String> swapped = nameAge.swap();System.out.println("原始: " + nameAge);System.out.println("转换: " + nameUpperCase);System.out.println("交换: " + swapped);nameAge.forEach((name, age) -> System.out.println("姓名: " + name + ", 年龄: " + age));// 使用Result记录类Result<Integer, String> successResult = Result.success(42);Result<Integer, String> failureResult = Result.failure("计算失败");System.out.println("\n成功结果: " + successResult);System.out.println("失败结果: " + failureResult);successResult.ifSuccess(value -> System.out.println("成功值: " + value));failureResult.ifFailure(error -> System.out.println("错误: " + error));Result<Integer, String> mapped = successResult.map(x -> x * 2);System.out.println("映射后: " + mapped);Integer defaultValue = failureResult.getOrElse(0);System.out.println("默认值: " + defaultValue);}
}

记录类与模式匹配(instanceof 模式匹配)

// 记录类 hierarchy
sealed interface Shape permits Circle, Rectangle, Triangle {double area();
}record Circle(double radius) implements Shape {@Overridepublic double area() {return Math.PI * radius * radius;}
}record Rectangle(double width, double height) implements Shape {@Overridepublic double area() {return width * height;}
}record Triangle(double base, double height) implements Shape {@Overridepublic double area() {return 0.5 * base * height;}
}// 使用模式匹配
class PatternMatchingDemo {public static void processShape(Shape shape) {// instanceof 模式匹配 (Java 16+)if (shape instanceof Circle c) {System.out.println("圆形 - 半径: " + c.radius() + ", 面积: " + c.area());} else if (shape instanceof Rectangle r) {System.out.println("矩形 - 宽: " + r.width() + ", 高: " + r.height() + ", 面积: " + r.area());} else if (shape instanceof Triangle t) {System.out.println("三角形 - 底: " + t.base() + ", 高: " + t.height() + ", 面积: " + t.area());}}// switch 表达式模式匹配 (Java 17+)public static String describeShape(Shape shape) {return switch (shape) {case Circle c -> "圆形(半径=" + c.radius() + ")";case Rectangle r -> "矩形(" + r.width() + "x" + r.height() + ")";case Triangle t -> "三角形(底=" + t.base() + ",高=" + t.height() + ")";};}// 嵌套模式匹配public static void processOptionalShape(Optional<Shape> optionalShape) {if (optionalShape instanceof Optional<Circle> opt && opt.isPresent()) {Circle c = opt.get();System.out.println("可选圆形: " + c.radius());}}public static void main(String[] args) {List<Shape> shapes = List.of(new Circle(5.0),new Rectangle(4.0, 6.0),new Triangle(3.0, 4.0));System.out.println("处理形状:");for (Shape shape : shapes) {processShape(shape);System.out.println("描述: " + describeShape(shape));System.out.println("---");}}
}

记录类序列化

import java.io.*;
import java.util.Base64;// 可序列化的记录类
public record UserRecord(String username, String email, int age) implements Serializable {private static final long serialVersionUID = 1L;// 紧凑构造方法public UserRecord {if (username == null || username.trim().isEmpty()) {throw new IllegalArgumentException("用户名不能为空");}if (email == null || !email.contains("@")) {throw new IllegalArgumentException("邮箱格式不正确");}username = username.trim();}// 自定义序列化逻辑private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();System.out.println("序列化用户: " + username);}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();System.out.println("反序列化用户: " + username);}// 静态工厂方法从序列化数据创建public static UserRecord fromSerializedData(byte[] data) {try (ByteArrayInputStream bis = new ByteArrayInputStream(data);ObjectInputStream ois = new ObjectInputStream(bis)) {return (UserRecord) ois.readObject();} catch (IOException | ClassNotFoundException e) {throw new RuntimeException("反序列化失败", e);}}// 转换为Base64序列化字符串public String toBase64() {try (ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos)) {oos.writeObject(this);return Base64.getEncoder().encodeToString(bos.toByteArray());} catch (IOException e) {throw new RuntimeException("序列化失败", e);}}
}class SerializationDemo {public static void main(String[] args) {UserRecord user = new UserRecord("john_doe", "john@example.com", 30);try {// 序列化到文件try (FileOutputStream fos = new FileOutputStream("user.ser");ObjectOutputStream oos = new ObjectOutputStream(fos)) {oos.writeObject(user);}// 从文件反序列化try (FileInputStream fis = new FileInputStream("user.ser");ObjectInputStream ois = new ObjectInputStream(fis)) {UserRecord deserializedUser = (UserRecord) ois.readObject();System.out.println("反序列化用户: " + deserializedUser);System.out.println("是否相等: " + user.equals(deserializedUser));}// 使用Base64序列化String base64Data = user.toBase64();System.out.println("Base64数据: " + base64Data.substring(0, 50) + "...");UserRecord fromBase64 = UserRecord.fromSerializedData(Base64.getDecoder().decode(base64Data));System.out.println("从Base64恢复: " + fromBase64);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}

记录类与集合框架(在集合中使用记录类)

import java.util.*;
import java.util.stream.*;public record Student(String id, String name, int score, String className) implements Comparable<Student> {// 紧凑构造方法public Student {if (score < 0 || score > 100) {throw new IllegalArgumentException("分数必须在0-100之间");}name = name != null ? name.trim() : "";className = className != null ? className.toUpperCase() : "";}// 实现Comparable接口@Overridepublic int compareTo(Student other) {return Integer.compare(other.score, this.score); // 按分数降序}// 成绩等级public String getGrade() {if (score >= 90) return "A";else if (score >= 80) return "B";else if (score >= 70) return "C";else if (score >= 60) return "D";else return "F";}public boolean isPassing() {return score >= 60;}
}class CollectionDemo {public static void main(String[] args) {List<Student> students = Arrays.asList(new Student("S001", "张三", 85, "CS101"),new Student("S002", "李四", 92, "CS101"),new Student("S003", "王五", 78, "MA101"),new Student("S004", "赵六", 45, "MA101"),new Student("S005", "钱七", 67, "CS101"));// 使用Stream API处理记录类集合System.out.println("所有学生:");students.forEach(System.out::println);System.out.println("\n按班级分组:");Map<String, List<Student>> byClass = students.stream().collect(Collectors.groupingBy(Student::className));byClass.forEach((className, classStudents) -> {System.out.println(className + ": " + classStudents);});System.out.println("\n成绩统计:");DoubleSummaryStatistics stats = students.stream().mapToInt(Student::score).summaryStatistics();System.out.printf("平均分: %.2f, 最高分: %d, 最低分: %d, 总数: %d%n",stats.getAverage(), stats.getMax(), stats.getMin(), stats.getCount());System.out.println("\n及格学生:");students.stream().filter(Student::isPassing).sorted().forEach(s -> System.out.println(s.name() + " - " + s.score() + " (" + s.getGrade() + ")"));System.out.println("\n不及格学生:");students.stream().filter(s -> !s.isPassing()).forEach(s -> System.out.println(s.name() + " - " + s.score()));// 使用Set(基于equals和hashCode)Set<Student> studentSet = new HashSet<>(students);System.out.println("\nSet中的学生数量: " + studentSet.size());// 使用Map(记录类作为键)Map<Student, String> studentNotes = new HashMap<>();students.forEach(s -> studentNotes.put(s, "备注: " + s.name()));System.out.println("\n学生备注:");studentNotes.forEach((student, note) -> System.out.println(student.name() + ": " + note));}
}

设计原则

// 1. 记录类应该是不可变的数据载体
public record ImmutablePoint(int x, int y) {// 好的设计:只有数据,没有可变状态public ImmutablePoint move(int dx, int dy) {return new ImmutablePoint(x + dx, y + dy);}
}// 2. 避免在记录类中封装复杂业务逻辑
public record SimpleData(String id, String value, long timestamp) {// 保持简单,只包含数据相关的方法public boolean isExpired() {return System.currentTimeMillis() - timestamp > 3600000; // 1小时}
}// 3. 合理使用紧凑构造方法进行验证
public record ValidatedEmail(String value) {public ValidatedEmail {if (value == null || !value.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {throw new IllegalArgumentException("无效的邮箱地址: " + value);}value = value.toLowerCase();}
}// 4. 为记录类提供合适的工厂方法
public record Currency(String code, String name, String symbol) {private static final Map<String, Currency> CURRENCIES = Map.of("USD", new Currency("USD", "US Dollar", "$"),"EUR", new Currency("EUR", "Euro", "€"),"JPY", new Currency("JPY", "Japanese Yen", "¥"));public static Currency of(String code) {Currency currency = CURRENCIES.get(code.toUpperCase());if (currency == null) {throw new IllegalArgumentException("未知货币代码: " + code);}return currency;}public static Set<String> availableCurrencies() {return CURRENCIES.keySet();}
}// 5. 记录类与模式匹配结合使用
class BestPracticesDemo {public static void processData(Object data) {switch (data) {case SimpleData sd -> System.out.println("简单数据: " + sd.value());case ValidatedEmail email -> System.out.println("验证邮箱: " + email.value());case Currency currency -> System.out.println("货币: " + currency.name());case null -> System.out.println("空数据");default -> System.out.println("未知数据类型");}}public static void main(String[] args) {processData(new SimpleData("1", "测试", System.currentTimeMillis()));processData(new ValidatedEmail("test@example.com"));processData(Currency.of("USD"));processData(null);}
}

总结

Java记录类的核心要点:

  1. 定义:使用record关键字,自动生成不可变数据类
  2. 自动生成:字段、构造方法、访问器、equals、hashCode、toString
  3. 紧凑构造方法:用于参数验证和规范化,无需显式赋值
  4. 自定义构造方法:必须调用主构造方法
  5. 方法支持:可以定义实例方法、静态方法、重写访问器
  6. 接口实现:可以实现多个接口
  7. 泛型支持:可以是泛型记录类
  8. 序列化:支持序列化,可以自定义序列化逻辑
  9. 模式匹配:与instanceof和switch模式匹配完美配合
  10. 不可变性:记录类本质上是不可变的
http://www.hskmm.com/?act=detail&tid=20983

相关文章:

  • OpenFeign 继承FeignClient客户端注意事项
  • 9月29日
  • JVM调优实战及常量池详解
  • Cisco Identity Services Engine (ISE) 3.5 - 基于身份的网络访问控制和策略实施系统
  • 03-控制台项目创建与结构说明
  • 赋能智慧应急:国标GB28181平台EasyGBS视频技术如何成为气象灾害预警新工具
  • NET各个版本新增的特性和语法糖
  • xinference推理embedding等小模型
  • day15-项目上线
  • opencv学习记录6
  • 努力的轨迹,通往成长的旅程——赵欣彤的自我介绍
  • 第2章 day02 requests基础
  • 线性代数_工程实践-计算实现numpy
  • 在HAL库使用printf打印串口信息
  • 第4章 day04 防盗链
  • 第3章 day03 xpath+反爬虫
  • 002- 学习环境搭建
  • 第10章 day10 DrissionPage详细教程
  • 求局部最小值
  • Element-UI的transfer穿梭框组件数据量大解决方案
  • 第9章 day09 hook插件
  • nginx 一致性hash和流量检查模块
  • 深入解析:10月底实习准备-Mysql(按面试频率准备)
  • 机器学习概述 - -一叶知秋
  • CEXE的%你赛5-题解
  • C++语言(1)
  • Windows多人共享文件夹全流程,附2025新共享文件快90%
  • 第11章 day11-day12关于json请求体/逆向爬虫实战
  • 容斥与二项式反演
  • react useCallback Hook详解