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: 20
student2.displayInfo(); // 输出: Name: Bob, Age: 22
// 每个对象有独立的实例变量副本
System.out.println(student1.name); // Alice
System.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: 2
Employee.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 = 1→x = b - 线程2执行:
b = 1→y = 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先执行
x = b(此时b=0,所以x=0) - 线程2先执行
y = a(此时a=0,所以y=0) - 然后两个线程分别执行赋值操作
结果: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不可能同时为0
if (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;
}
@Override
public 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的场景
- 状态标志 - 简单的boolean标志,用于控制线程执行
- 一次性安全发布 - 确保对象构造完成后才对其他线程可见
- 独立观察 - 定期"发布"观察结果供程序使用
- 双重检查锁定 - 与synchronized配合实现延迟初始化
总结:不使用volatile的场景
- 复合操作 - i++、check-then-act等需要原子性的操作
- 多个相关变量 - 需要同时更新多个相关变量时
- 频繁写入 - 写入频繁且需要原子性时,考虑使用锁
总结: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; // 会话ID
public 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();
}
@Override
protected 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;
// 不可序列化的对象必须标记为transient
private 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 关键字的主要用途
-
安全保护
- 防止敏感信息(密码、密钥等)被持久化
- 避免安全漏洞
-
资源优化
- 减少序列化数据大小
- 避免序列化大型临时数据
-
运行时状态管理
- 不保存临时状态信息
- 重新创建对象时初始化新状态
-
不可序列化对象处理
- 处理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 message
System.out.println("Parent: " + super.message); // 输出:Parent message
}
}
调用父类的方法
class Vehicle {
public void start() {
System.out.println("Vehicle starting...");
}
}
class Car extends Vehicle {
@Override
public 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;
}
@Override
public 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;
}
@Override
public 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;
}
}
注意事项
- 构造方法调用顺序:使用
this()或super()调用构造方法时,必须放在方法的第一行 - 不能同时使用:在同一个构造方法中不能同时使用
this()和super() - 静态上下文:在静态方法中不能使用
this和super - 继承关系:
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 |
使用 PI 和 pow() 代替 Math.PI 和 Math.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; // 导入静态方法
作用:
- 这行代码告诉编译器:“当我写下
PI和pow时,我指的是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方法
@Override
public 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普通类的核心:
- 封装性:通过访问修饰符控制成员的可见性
- 构造方法:对象初始化,支持重载
- 成员方法:实现类的行为,支持重载
- 静态成员:类级别的变量和方法
- 代码块:初始化代码的执行
- this关键字:引用当前对象
- 包管理:组织类和命名空间
内部类
内部类(Inner Class)是定义在另一个类内部的类。Java 提供了四种类型的内部类:
- 成员内部类(Member Inner Class)
- 静态内部类(Static Nested Class)
- 局部内部类(Local Inner Class)
- 匿名内部类(Anonymous Inner Class)
成员内部类
成员内部类是最普通的内部类,它定义在外部类的内部,就像外部类的一个成员。
public class OuterClass {
private String outerField = "外部类字段";
// 成员内部类
class InnerClass {
private String innerField = "内部类字段";
public void display() {
// 内部类可以直接访问外部类的私有成员
System.out.println("访问外部类字段: " + outerField);
System.out.println("访问内部类字段: " + innerField);
}
}
public void createInner() {
InnerClass inner = new InnerClass();
inner.display();
}
}
实例化方式
public class Test {
public static void main(String[] args) {
// 方式1:通过外部类实例创建内部类实例
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner1 = outer.new InnerClass();
// 方式2:在外部类内部创建(推荐)
outer.createInner();
}
}
访问外部类成员
public class OuterClass {
private String message = "Hello";
class InnerClass {
private String message = "World";
public void showMessages() {
System.out.println("内部类message: " + this.message);
System.out.println("外部类message: " + OuterClass.this.message);
}
}
}
静态内部类
静态内部类使用 static 修饰,它不能直接访问外部类的非静态成员。
public class OuterClass {
private String instanceField = "实例字段";
private static String staticField = "静态字段";
// 静态内部类
static class StaticInnerClass {
public void display() {
// 可以访问外部类的静态成员
System.out.println("静态字段: " + staticField);
// 不能直接访问外部类的实例成员
// System.out.println(instanceField); // 编译错误
}
public static void staticMethod() {
System.out.println("静态内部类的静态方法");
}
}
}
实例化方式
public class Test {
public static void main(String[] args) {
// 静态内部类不需要外部类实例
OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();
staticInner.display();
// 调用静态内部类的静态方法
OuterClass.StaticInnerClass.staticMethod();
}
}
局部内部类
局部内部类定义在方法或作用域内,只在定义它的块中可见。
public class OuterClass {
private String outerField = "外部字段";
public void methodWithLocalClass() {
final String localVar = "局部变量";
// 局部内部类
class LocalInnerClass {
private String innerField = "局部内部类字段";
public void display() {
System.out.println("外部字段: " + outerField);
System.out.println("局部变量: " + localVar); // 只能访问final或等效final的局部变量
System.out.println("内部字段: " + innerField);
}
}
// 在方法内部使用局部内部类
LocalInnerClass local = new LocalInnerClass();
local.display();
}
public void anotherMethod() {
// 这里不能访问 LocalInnerClass,因为它在另一个方法的作用域内
}
}
访问局部变量的限制
public class OuterClass {
public void demonstrateFinal() {
int normalVar = 10;
final int finalVar = 20;
// Java 8+ 中,等效final的变量也可以访问
int effectivelyFinal = 30;
class LocalClass {
public void show() {
// System.out.println(normalVar); // 编译错误:必须为final或等效final
System.out.println(finalVar); // 可以访问
System.out.println(effectivelyFinal); // 可以访问(等效final)
}
}
// normalVar = 100; // 如果取消注释,effectivelyFinal就不再是等效final
new LocalClass().show();
}
}
匿名内部类
匿名内部类没有类名,通常用于实现接口或继承类。
// 接口定义
interface Greeting {
void sayHello(String name);
}
// 抽象类定义
abstract class Animal {
abstract void makeSound();
}
public class AnonymousClassExample {
public void demonstrateAnonymousClasses() {
// 实现接口的匿名内部类
Greeting greeting = new Greeting() {
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
};
// 继承抽象类的匿名内部类
Animal animal = new Animal() {
@Override
void makeSound() {
System.out.println("Anonymous animal makes sound!");
}
// 可以添加额外的方法,但只能通过匿名类内部访问
public void extraMethod() {
System.out.println("Extra method");
}
};
greeting.sayHello("World");
animal.makeSound();
// animal.extraMethod(); // 编译错误,Animal类型没有这个方法
}
}
在方法参数中使用
public class AnonymousClassInMethod {
public void process(Runnable task) {
new Thread(task).start();
}
public void demonstrate() {
// 匿名内部类作为方法参数
process(new Runnable() {
@Override
public void run() {
System.out.println("Running in anonymous class");
}
});
// Java 8+ 可以使用lambda表达式替代
process(() -> System.out.println("Running with lambda"));
}
}
内部类的特殊特性
多重嵌套
public class MultiLevelNesting {
class Level1 {
class Level2 {
class Level3 {
public void showLevel() {
System.out.println("三级嵌套内部类");
}
}
}
}
public void test() {
Level1.Level2.Level3 level3 = new Level1().new Level2().new Level3();
level3.showLevel();
}
}
内部类继承
public class OuterForInheritance {
class Inner {
protected String value = "Inner value";
}
}
class SubClass extends OuterForInheritance.Inner {
// 需要提供外部类引用
public SubClass(OuterForInheritance outer) {
outer.super(); // 调用外部类的super()
}
public void show() {
System.out.println("Value: " + value);
}
}
接口中的内部类
interface InterfaceWithInnerClass {
void interfaceMethod();
// 接口中的内部类默认是static和public的
class InnerClassInInterface {
public void helperMethod() {
System.out.println("Helper method in interface inner class");
}
}
}
public class TestInterfaceInner {
public static void main(String[] args) {
InterfaceWithInnerClass.InnerClassInInterface helper =
new InterfaceWithInnerClass.InnerClassInInterface();
helper.helperMethod();
}
}
内部类的应用
迭代器模式
import java.util.Iterator;
public class CustomCollection<T> implements Iterable<T> {
private T[] elements;
private int size;
public CustomCollection(int capacity) {
elements = (T[]) new Object[capacity];
size = 0;
}
public void add(T element) {
if (size < elements.length) {
elements[size++] = element;
}
}
@Override
public Iterator<T> iterator() {
return new CustomIterator();
}
// 内部类实现迭代器
private class CustomIterator implements Iterator<T> {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < size;
}
@Override
public T next() {
if (!hasNext()) {
throw new java.util.NoSuchElementException();
}
return elements[currentIndex++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}
回调机制
public class Button {
private ClickListener clickListener;
// 内部接口
public interface ClickListener {
void onClick();
}
public void setClickListener(ClickListener listener) {
this.clickListener = listener;
}
public void click() {
if (clickListener != null) {
clickListener.onClick();
}
}
}
public class GUIApplication {
public static void main(String[] args) {
Button button = new Button();
// 使用匿名内部类实现回调
button.setClickListener(new Button.ClickListener() {
@Override
public void onClick() {
System.out.println("按钮被点击了!");
}
});
button.click();
}
}
内部类的内存管理和注意事项
内存泄漏风险
public class MemoryLeakExample {
private byte[] largeData = new byte[1024 * 1024]; // 1MB
class InnerClass {
public void holdReference() {
System.out.println("持有外部类引用");
}
}
public InnerClass getInner() {
return new InnerClass();
}
public static void main(String[] args) {
MemoryLeakExample outer = new MemoryLeakExample();
Object inner = outer.getInner();
outer = null; // 外部类实例不会被GC,因为内部类持有引用
// 解决方案:使用静态内部类或者弱引用
}
}
序列化问题
import java.io.Serializable;
public class SerializationExample implements Serializable {
private String data = "重要数据";
// 内部类要实现序列化需要显式实现Serializable
class InnerClass implements Serializable {
private String innerData = "内部数据";
}
}
内部类编译与普通类编译
编译后生成的类文件
普通类的编译
// 普通类
public class NormalClass {
private String field;
public void method() {
System.out.println("Normal method");
}
}
编译结果:
NormalClass.class
内部类的编译
public class OuterClass {
private String outerField;
// 成员内部类
class MemberInner {
private String innerField;
}
// 静态内部类
static class StaticInner {
private String staticField;
}
public void method() {
// 局部内部类
class LocalInner {
private String localField;
}
// 匿名内部类
Runnable anonymous = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous");
}
};
}
}
编译结果:
OuterClass.class
OuterClass$MemberInner.class
OuterClass$StaticInner.class
OuterClass$1LocalInner.class // 局部内部类
OuterClass$1.class // 匿名内部类
字节码结构差异
访问外部类字段的机制
源代码:
public class Outer {
private String outerField = "outer";
class Inner {
public void accessOuter() {
System.out.println(outerField);
}
}
}
编译后的字节码分析:
// 反编译 Outer$Inner.class 可以看到:
class Outer$Inner {
// 编译器自动添加的final引用指向外部类实例
private final Outer this$0;
// 编译器生成的构造函数
Outer$Inner(Outer outer) {
this.this$0 = outer;
super();
}
public void accessOuter() {
// 通过合成引用访问外部类字段
System.out.println(this$0.outerField);
}
}
实际编译过程验证
让我们创建一个测试类来验证:
测试类:
// Outer.java
public class Outer {
private int outerValue = 10;
public class Inner {
private int innerValue = 20;
public int sum() {
return outerValue + innerValue;
}
}
public static class StaticInner {
private int staticValue = 30;
}
}
编译和反编译验证:
# 编译
javac Outer.java
# 查看生成的类文件
ls *.class
# Outer.class, Outer$Inner.class, Outer$StaticInner.class
# 使用javap查看字节码
javap -c Outer
javap -c Outer\$Inner
javap -c Outer\$StaticInner
构造函数差异
普通类的构造函数
public class NormalClass {
public NormalClass() {
// 默认构造函数
}
public NormalClass(String param) {
// 带参数构造函数
}
}
编译后:
- 构造函数保持原样
内部类的构造函数
public class Outer {
private String outerField;
class Inner {
// 看起来无参的构造函数
Inner() {
System.out.println("Inner constructor");
}
}
}
实际编译结果:
// 反编译后的Inner类
class Outer$Inner {
private final Outer this$0;
// 编译器添加了外部类参数
Outer$Inner(Outer outer) {
this.this$0 = outer;
super();
System.out.println("Inner constructor");
}
}
访问控制差异
访问私有成员
public class Outer {
private String privateField = "private";
class Inner {
public void accessPrivate() {
// 内部类可以直接访问外部类的私有成员
System.out.println(privateField);
}
}
}
编译处理:
编译器会为外部类生成合成访问方法(synthetic accessor methods):
// 实际编译时,编译器会为Outer类生成:
class Outer {
private String privateField = "private";
// 编译器生成的合成访问方法
static String access$000(Outer obj) {
return obj.privateField;
}
}
// Inner类实际调用的是:
class Outer$Inner {
public void accessPrivate() {
System.out.println(Outer.access$000(this$0));
}
}
局部内部类和匿名内部类的特殊处理
局部内部类访问局部变量
public class Outer {
public void method() {
final String localVar = "local";
int effectivelyFinal = 42;
class LocalInner {
public void print() {
System.out.println(localVar + effectivelyFinal);
}
}
}
}
编译处理:
// 编译器生成的LocalInner类
class Outer$1LocalInner {
// 编译器添加的final字段保存局部变量的副本
private final String val$localVar;
private final int val$effectivelyFinal;
private final Outer this$0;
// 构造函数接收所有需要访问的局部变量
Outer$1LocalInner(Outer outer, String param1, int param2) {
this.this$0 = outer;
this.val$localVar = param1;
this.val$effectivelyFinal = param2;
super();
}
public void print() {
System.out.println(val$localVar + val$effectivelyFinal);
}
}
匿名内部类
public class Outer {
public void method() {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Running");
}
};
}
}
编译结果:
Outer$1.class // 匿名内部类文件
反编译结果:
// Outer$1.class
final class Outer$1 implements Runnable {
private final Outer this$0;
Outer$1(Outer outer) {
this.this$0 = outer;
super();
}
@Override
public void run() {
System.out.println("Running");
}
}
静态内部类的特殊处理
静态内部类不持有外部类引用
public class Outer {
private static String staticField = "static";
private String instanceField = "instance";
static class StaticInner {
public void access() {
System.out.println(staticField); // 可以访问
// System.out.println(instanceField); // 编译错误
}
}
}
编译特点:
- 不生成
this$0字段 - 可以直接访问外部类的静态成员
- 编译为独立的类文件
实际编译验证
测试代码:
// CompileTest.java
public class CompileTest {
private String instanceField = "instance";
private static String staticField = "static";
// 成员内部类
class MemberInner {
void access() {
System.out.println(instanceField + staticField);
}
}
// 静态内部类
static class StaticInner {
void access() {
System.out.println(staticField);
}
}
public void testLocal() {
final String local = "local";
// 局部内部类
class LocalInner {
void access() {
System.out.println(local + instanceField);
}
}
// 匿名内部类
Runnable anonymous = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous: " + instanceField);
}
};
}
}
编译验证步骤:
# 编译
javac CompileTest.java
# 查看所有生成的类文件
ls -la *.class
# 使用javap分析字节码
javap -v CompileTest
javap -v CompileTest\$MemberInner
javap -v CompileTest\$StaticInner
javap -v 'CompileTest$1LocalInner'
javap -v 'CompileTest$1'
编译优化的影响
合成方法和字段
编译器会生成以下合成元素:
this$0:成员内部类持有外部类实例的引用val$localVar:局部内部类持有局部变量的副本access$000():访问私有成员的合成方法
调试信息
内部类的调试信息包含:
- 特殊的命名规则
- 行号映射
- 源文件关联
主要区别
| 特性 | 普通类 | 内部类 |
|---|---|---|
| 类文件命名 | ClassName.class |
OuterClass$InnerClass.class |
| 外部类引用 | 无 | 自动添加 this$0 字段 |
| 构造函数 | 保持原样 | 自动添加外部类参数 |
| 访问控制 | 正常访问规则 | 可访问外部类私有成员 |
| 局部变量访问 | 不适用 | 通过合成字段保存副本 |
| 静态上下文 | 正常 | 静态内部类不持有外部引用 |
| 内存占用 | 独立 | 成员内部类依赖外部实例 |
抽象类 (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;
}
@Override
public void start() {
System.out.println(brand + " " + model + " 汽车启动");
}
@Override
public 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() {
// 默认空实现
}
}
抽象类的继承
抽象类继承抽象类
当一个抽象类继承另一个抽象类时,可以:
- 实现部分父类的抽象方法
- 保持其他抽象方法不变
- 添加新的抽象方法
这种设计允许在继承链中:
- 提供通用实现(如所有哺乳动物睡觉方式相似)
- 强制特定实现(如不同动物吃的方式不同)
- 逐步具体化,减少代码重复
这就是面向对象设计中"抽象层次逐步具体化"的典型应用
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;
}
// 可以实现部分抽象方法
@Override
public void sleep() {
System.out.println(name + " 正在睡觉");
}
// 可以添加新的抽象方法
public abstract void giveBirth();
// eat方法仍然保持抽象,由具体子类实现
}
// 具体类继承抽象类
class Dog extends AbstractMammal {
public Dog(String name, boolean hasFur) {
super(name, hasFur);
}
@Override
public void eat() {
System.out.println(name + " 在吃狗粮");
}
@Override
public 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 {
@Override
public void method1() {
System.out.println("实现method1");
}
@Override
public 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;
}
// 实现部分接口方法
@Override
public 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;
}
// 必须实现所有接口的抽象方法,或者声明为抽象
@Override
public abstract void fly();
@Override
public abstract void land();
@Override
public abstract void swim();
@Override
public abstract void dive();
}
// 具体实现
class MallardDuck extends Duck {
public MallardDuck(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(name + " 在飞行");
}
@Override
public void land() {
System.out.println(name + " 降落在水面上");
}
@Override
public void swim() {
System.out.println(name + " 在游泳");
}
@Override
public 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 {
@Override
protected void processData() {
System.out.println("处理CSV数据...");
}
@Override
protected boolean needValidation() {
return true;
}
@Override
protected void validateData() {
System.out.println("验证CSV数据格式...");
}
}
class XMLProcessor extends DataProcessor {
@Override
protected 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;
}
@Override
public void draw() {
System.out.println("绘制圆形: 中心(" + x + ", " + y + "), 半径=" + radius + ", 颜色=" + color);
}
@Override
public void resize(double scale) {
this.radius *= scale;
System.out.println("圆形缩放,新半径: " + radius);
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
public 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;
}
@Override
public void draw() {
System.out.println("绘制矩形: 左上角(" + x + ", " + y + "), 宽=" + width + ", 高=" + height + ", 颜色=" + color);
}
@Override
public void resize(double scale) {
this.width *= scale;
this.height *= scale;
System.out.println("矩形缩放,新尺寸: " + width + "x" + height);
}
@Override
public double calculateArea() {
return width * height;
}
@Override
public 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);
}
@Override
public void create() {
System.out.println("创建Word文档: " + title);
this.content = "Word文档内容";
}
@Override
public void save() {
System.out.println("保存Word文档为 .docx 格式");
}
@Override
public void print() {
System.out.println("打印Word文档");
}
@Override
protected void edit() {
super.edit();
System.out.println("使用Word特定功能编辑");
}
}
class PDFDocument extends Document {
public PDFDocument(String title) {
super(title);
}
@Override
public void create() {
System.out.println("创建PDF文档: " + title);
this.content = "PDF文档内容";
}
@Override
public void save() {
System.out.println("保存PDF文档为 .pdf 格式");
}
@Override
public 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抽象类的核心要点:
- 定义:使用
abstract关键字,不能实例化 - 抽象方法:没有方法体,必须由子类实现
- 构造方法:可以有,用于子类初始化
- 具体方法:可以有实现的方法
- 继承规则:必须实现所有抽象方法,或者声明为抽象类
- 设计模式:常用于模板方法模式、工厂方法模式等
- 与接口比较:适合共享代码、维护状态、定义模板方法的场景
接口 (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 final
public 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 abstract
public 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;
@Override
public void method1() {
System.out.println("实现 method1");
}
@Override
public void method2() {
System.out.println("实现 method2");
}
@Override
public void method3() {
System.out.println("实现 method3");
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public boolean isValid(int value) {
return value > 0;
}
@Override
public 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类的方法,但不推荐
@Override
default String toString() {
return "DefaultMethodExample实例";
}
}
// 实现类可以选择重写默认方法
class DefaultMethodImpl implements DefaultMethodExample {
@Override
public void performAction() {
System.out.println("执行具体动作");
}
// 可选:重写默认方法
@Override
public String getDefaultName() {
return "自定义名称";
}
}
// 实现类也可以不重写默认方法
class SimpleImpl implements DefaultMethodExample {
@Override
public 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 {
@Override
public void conflictMethod() {
System.out.println("重写冲突方法");
// 可以选择调用特定的接口方法
InterfaceA.super.conflictMethod();
}
}
// 解决方案2:选择其中一个接口
class Solution2 implements InterfaceA {
// 使用 InterfaceA 的默认方法
}
interface InterfaceC extends InterfaceA {
// 解决方案3:在接口中重写
@Override
default 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 {
@Override
public 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();
@Override
default void breathe() {
System.out.println("浮出水面呼吸");
}
}
// 具体实现
class Dolphin implements AquaticMammal {
@Override
public void eat() {
System.out.println("吃鱼");
}
@Override
public void sleep() {
System.out.println("水中睡觉");
}
@Override
public void giveBirth() {
System.out.println("生小海豚");
}
@Override
public void swim() {
System.out.println("快速游泳");
}
@Override
public 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() 方法的冲突
@Override
default void open() {
System.out.println("打开读写流");
Readable.super.open(); // 调用 Readable 的 open
Writable.super.open(); // 调用 Writable 的 open
}
// 添加新方法
void flush();
}
class FileProcessor implements ReadWritable {
private String content = "";
@Override
public String read() {
return content;
}
@Override
public void write(String content) {
this.content = content;
}
@Override
public 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;
}
@Override
public void fly() {
System.out.println(name + " 在飞行");
}
@Override
public void swim() {
System.out.println(name + " 在游泳");
}
@Override
public void run() {
System.out.println(name + " 在奔跑");
}
// 可以重写默认方法
@Override
public 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 - 接受一个参数,返回boolean
Predicate<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);
@Override
default boolean validatePayment() {
System.out.println("验证可退款支付");
return true;
}
}
// 国际支付接口
interface InternationalPayment extends Payment {
double getExchangeRate(String fromCurrency, String toCurrency);
BigDecimal calculateFee(BigDecimal amount);
@Override
default 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();
}
@Override
public 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());
}
@Override
public boolean validatePayment() {
System.out.println("验证支付宝支付");
return true;
}
@Override
public String getPaymentId() {
return paymentId;
}
@Override
public 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();
}
@Override
public String processPayment(BigDecimal amount, String currency) {
// 使用接口的默认实现
String result = InternationalPayment.super.processPayment(amount, currency);
return "PayPal " + result;
}
@Override
public boolean validatePayment() {
System.out.println("验证PayPal支付");
return true;
}
@Override
public String getPaymentId() {
return paymentId;
}
@Override
public double getExchangeRate(String fromCurrency, String toCurrency) {
// 模拟汇率
if ("USD".equals(fromCurrency) && "CNY".equals(toCurrency)) {
return 6.5;
}
return 1.0;
}
@Override
public 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 {
@Override
public 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 {
@Override
public 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 {
@Override
public String fetchData() {
return "数据库数据";
}
}
class ApiService implements DataService {
@Override
public 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接口的核心要点:
- 定义:使用
interface关键字,支持多继承 - 常量:默认
public static final - 抽象方法:默认
public abstract - 默认方法:Java 8+,有方法体,可被重写
- 静态方法:Java 8+,通过接口名调用
- 私有方法:Java 9+,接口内部使用
- 函数式接口:只有一个抽象方法,支持Lambda
- 标记接口:没有任何方法的接口
- 设计模式:广泛应用于策略模式、工厂模式等
枚举 (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方法
@Override
public 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("停止", "红色") {
@Override
public TrafficLight next() {
return GREEN;
}
},
YELLOW("警告", "黄色") {
@Override
public TrafficLight next() {
return RED;
}
},
GREEN("通行", "绿色") {
@Override
public TrafficLight next() {
return YELLOW;
}
};
private final String description;
private final String color;
TrafficLight(String description, String color) {
this.description = description;
this.color = color;
}
// 实现接口方法
@Override
public String getDescription() {
return description;
}
@Override
public 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 {
@Override
public double apply(double x, double y) {
return x + y;
}
@Override
public String getSymbol() {
return "+";
}
},
SUBTRACT {
@Override
public double apply(double x, double y) {
return x - y;
}
@Override
public String getSymbol() {
return "-";
}
},
MULTIPLY {
@Override
public double apply(double x, double y) {
return x * y;
}
@Override
public String getSymbol() {
return "*";
}
},
DIVIDE {
@Override
public double apply(double x, double y) {
if (y == 0) throw new ArithmeticException("除数不能为零");
return x / y;
}
@Override
public 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和Setter
public 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 {
@Override
public void sendNotification(String message, String recipient) {
System.out.println("发送邮件到 " + recipient + ": " + message);
}
@Override
public boolean validateRecipient(String recipient) {
return recipient != null && recipient.contains("@");
}
},
SMS {
@Override
public void sendNotification(String message, String recipient) {
System.out.println("发送短信到 " + recipient + ": " + message);
}
@Override
public boolean validateRecipient(String recipient) {
return recipient != null && recipient.matches("\\d{11}");
}
},
PUSH {
@Override
public void sendNotification(String message, String recipient) {
System.out.println("发送推送通知到设备 " + recipient + ": " + message);
}
@Override
public boolean validateRecipient(String recipient) {
return recipient != null && recipient.startsWith("device_");
}
},
SLACK {
@Override
public void sendNotification(String message, String recipient) {
System.out.println("发送Slack消息到频道 " + recipient + ": " + message);
}
@Override
public 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 {
@Override
public OrderStatus next() {
return PAID;
}
@Override
public boolean canCancel() {
return true;
}
},
PAID {
@Override
public OrderStatus next() {
return SHIPPED;
}
@Override
public boolean canCancel() {
return true;
}
},
SHIPPED {
@Override
public OrderStatus next() {
return DELIVERED;
}
@Override
public boolean canCancel() {
return false;
}
},
DELIVERED {
@Override
public OrderStatus next() {
return COMPLETED;
}
@Override
public boolean canCancel() {
return false;
}
},
COMPLETED {
@Override
public OrderStatus next() {
return this; // 最终状态,不能再转换
}
@Override
public boolean canCancel() {
return false;
}
},
CANCELLED {
@Override
public OrderStatus next() {
return this; // 最终状态
}
@Override
public 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());
}
}
// Getter
public OrderStatus getStatus() {
return status;
}
}
class StateMachineDemo {
public static void main(String[] args) {
Order order = new Order("ORDER_001");
// 正常流程
order.proceedToNext(); // CREATED -> PAID
order.proceedToNext(); // PAID -> SHIPPED
// 尝试取消(应该失败)
order.cancel();
order.proceedToNext(); // SHIPPED -> DELIVERED
order.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枚举的核心要点:
- 定义:使用
enum关键字,隐含继承java.lang.Enum - 常量:枚举常量是类的实例,在类加载时创建
- 构造方法:必须是private,在常量声明时调用
- 方法:可以有实例方法、静态方法、抽象方法
- 接口:枚举可以实现接口
- 内置方法:
values(),valueOf(),name(),ordinal()等 - 集合支持:
EnumSet和EnumMap提供高性能操作 - 设计模式:完美实现单例模式、策略模式、状态机等
- 线程安全:枚举实例创建是线程安全的
注解 (Annotation)
注解的定义和基本概念
注解定义语法
[访问修饰符] @interface 注解名 {
// 注解元素(方法)
// 默认值
}
基本注解示例
// 最简单的注解
public @interface MyAnnotation {
}
// 使用注解
@MyAnnotation
class MyClass {
@MyAnnotation
public 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 - 表示方法重写
@Override
public 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 - 表示方法不会对可变参数进行危险操作
@SafeVarargs
public final <T> void safeMethod(T... args) {
for (T arg : args) {
System.out.println(arg);
}
}
// @FunctionalInterface - 函数式接口
@FunctionalInterface
interface 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("获取用户信息");
}
@MyRuntimeAnnotation
public 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 setters
public 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 {
@Override
public 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,}$";
@Override
public void initialize(ValidEmail constraintAnnotation) {
}
@Override
public 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;
@Override
public void initialize(ValidRange constraintAnnotation) {
this.min = constraintAnnotation.min();
this.max = constraintAnnotation.max();
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return false;
}
return value >= min && value <= max;
}
}
// 使用验证注解的类
class User {
@ValidEmail
private String email;
@ValidRange(min = 1, max = 120)
private Integer age;
// 构造方法、getter、setter
public 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 {
@Autowired
private 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;
@BeforeClass
public static void setUpClass() {
System.out.println("测试类初始化");
}
@Before
public void setUp() {
calculator = new Calculator();
System.out.println("测试前准备");
}
@Test
public 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("暂时跳过")
@Test
public void testIgnored() {
System.out.println("这个测试被跳过了");
}
@After
public void tearDown() {
calculator = null;
System.out.println("测试后清理");
}
@AfterClass
public 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、setter
public User() {}
public User(String username, String email) {
this.username = username;
this.email = email;
}
// getter和setter
public 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、setter
public 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注解的核心要点:
- 定义:使用
@interface关键字,本质是接口 - 元素:可以定义各种类型的元素(方法),支持默认值
- 元注解:
@Target,@Retention,@Documented,@Inherited,@Repeatable - 保留策略:
SOURCE,CLASS,RUNTIME - 处理方式:编译时处理(注解处理器)或运行时处理(反射)
- 内置注解:
@Override,@Deprecated,@SuppressWarnings,@SafeVarargs,@FunctionalInterface - 应用场景:配置、验证、代码生成、框架集成等
记录 (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: true
System.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; }
@Override
public 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);
}
@Override
public int hashCode() {
return Objects.hash(name, age, email);
}
@Override
public 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);
}
// 静态方法生成ID
private 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(".");
}
// 重写访问器方法
@Override
public 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以包含静态信息
@Override
public 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接口
@Override
public String getId() {
return id;
}
@Override
public boolean isValid() {
return id != null && !id.trim().isEmpty() &&
name != null && !name.trim().isEmpty() &&
price >= 0 && stock >= 0;
}
// 实现Auditable接口
@Override
public void audit() {
System.out.printf("产品审计: %s (ID: %s, 价格: %.2f, 库存: %d)%n",
name, id, price, stock);
}
// 实现JsonSerializable接口
@Override
public 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
@Override
public 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 {
@Override
public double area() {
return Math.PI * radius * radius;
}
}
record Rectangle(double width, double height) implements Shape {
@Override
public double area() {
return width * height;
}
}
record Triangle(double base, double height) implements Shape {
@Override
public 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接口
@Override
public 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记录类的核心要点:
- 定义:使用
record关键字,自动生成不可变数据类 - 自动生成:字段、构造方法、访问器、equals、hashCode、toString
- 紧凑构造方法:用于参数验证和规范化,无需显式赋值
- 自定义构造方法:必须调用主构造方法
- 方法支持:可以定义实例方法、静态方法、重写访问器
- 接口实现:可以实现多个接口
- 泛型支持:可以是泛型记录类
- 序列化:支持序列化,可以自定义序列化逻辑
- 模式匹配:与instanceof和switch模式匹配完美配合
- 不可变性:记录类本质上是不可变的

浙公网安备 33010602011771号