本文目录导读:

我来给你展示一个完整的Java不可变类案例,包含多个实例和最佳实践。
经典不可变类案例
基本不可变类
import java.util.Date;
import java.util.Objects;
/**
* 一个经典的不可变类示例
* 实现不可变类的5条规则:
* 1. 类用final修饰
* 2. 所有字段用private final修饰
* 3. 不提供修改字段的方法(setter)
* 4. 构造器需要初始化所有字段
* 5. 引用类型字段需要深拷贝保护
*/
public final class Person {
// 1. 所有字段都是private final
private final String name;
private final int age;
private final Date birthDate; // 可变对象
// 2. 构造器初始化所有字段
public Person(String name, int age, Date birthDate) {
this.name = name;
this.age = age;
// 防御性拷贝:防止外部引用修改内部状态
this.birthDate = new Date(birthDate.getTime());
}
// 3. 只提供getter方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
// 4. 返回防御性拷贝,不直接返回引用
public Date getBirthDate() {
return new Date(birthDate.getTime());
}
// 5. equals和hashCode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name) &&
Objects.equals(birthDate, person.birthDate);
}
@Override
public int hashCode() {
return Objects.hash(name, age, birthDate);
}
@Override
public String toString() {
return String.format("Person{name='%s', age=%d, birthDate=%s}",
name, age, birthDate);
}
}
使用Builder模式的不可变类
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 使用Builder模式创建不可变类
* 适合字段较多的场景
*/
public final class Employee {
private final String employeeId;
private final String name;
private final String department;
private final double salary;
private final List<String> skills; // 可变集合
private final Address address; // 引用另一个对象
// 私有构造器,必须传入Builder
private Employee(Builder builder) {
this.employeeId = builder.employeeId;
this.name = builder.name;
this.department = builder.department;
this.salary = builder.salary;
// 深拷贝或不可修改集合
this.skills = builder.skills == null ?
Collections.emptyList() :
Collections.unmodifiableList(new ArrayList<>(builder.skills));
// 不可变对象引用可以直接赋值
this.address = builder.address;
}
// Getter方法
public String getEmployeeId() {
return employeeId;
}
public String getName() {
return name;
}
public String getDepartment() {
return department;
}
public double getSalary() {
return salary;
}
// 返回不可修改的集合视图
public List<String> getSkills() {
return skills;
}
// 返回对象引用(Address是不可变类)
public Address getAddress() {
return address;
}
// 静态Builder类
public static class Builder {
// 必填字段
private final String employeeId;
private final String name;
// 可选字段,设置默认值
private String department = "未分配";
private double salary = 0.0;
private List<String> skills;
private Address address;
// 构造器必须包含必填字段
public Builder(String employeeId, String name) {
this.employeeId = employeeId;
this.name = name;
}
// 可选字段的链式调用方法
public Builder department(String department) {
this.department = department;
return this;
}
public Builder salary(double salary) {
this.salary = salary;
return this;
}
public Builder skills(List<String> skills) {
this.skills = new ArrayList<>(skills);
return this;
}
public Builder address(Address address) {
this.address = address;
return this;
}
// build方法创建Employee实例
public Employee build() {
return new Employee(this);
}
}
@Override
public String toString() {
return String.format("Employee{id='%s', name='%s', dept='%s', salary=%.2f, skills=%s}",
employeeId, name, department, salary, skills);
}
}
/**
* 另一个不可变类,作为Employee的属性
*/
public final class Address {
private final String street;
private final String city;
private final String zipCode;
public Address(String street, String city, String zipCode) {
this.street = street;
this.city = city;
this.zipCode = zipCode;
}
// 所有字段都有getter,没有setter
public String getStreet() {
return street;
}
public String getCity() {
return city;
}
public String getZipCode() {
return zipCode;
}
}
使用record实现不可变类(Java 14+)
/**
* Java 14+ 使用record定义不可变类
* record自动生成:构造器、equals、hashCode、toString
*/
public record Product(String id, String name, double price) {
// 紧凑构造器:可以添加校验逻辑
public Product {
Objects.requireNonNull(id, "id不能为空");
Objects.requireNonNull(name, "name不能为空");
if (price < 0) {
throw new IllegalArgumentException("价格不能为负数");
}
}
// 可以添加方法
public boolean isExpensive() {
return price > 10000;
}
// 静态方法
public static Product of(String id, String name, double price) {
return new Product(id, name, price);
}
}
完整的测试示例
public class ImmutableDemo {
public static void main(String[] args) throws Exception {
// 1. 测试基本不可变类
System.out.println("=== 测试基本不可变类 ===");
Date birthDate = new Date();
Person person = new Person("张三", 25, birthDate);
// 尝试修改原始Date对象
birthDate.setTime(0L); // 修改传入的Date
System.out.println("Person的birthDate: " + person.getBirthDate());
// 尝试修改getter返回的对象
Date bd = person.getBirthDate();
bd.setTime(123456789L); // 修改返回的Date
System.out.println("再次访问birthDate: " + person.getBirthDate());
// 2. 测试Builder模式
System.out.println("\n=== 测试Builder模式 ===");
List<String> skills = new ArrayList<>();
skills.add("Java");
skills.add("Spring");
Employee employee = new Employee.Builder("EMP001", "李四")
.department("技术部")
.salary(15000)
.skills(skills)
.address(new Address("北京路1号", "北京市", "100000"))
.build();
// 修改外部skills列表
skills.add("Python");
System.out.println("Employee技能: " + employee.getSkills());
// 3. 测试record
System.out.println("\n=== 测试record ===");
Product product = new Product("P001", "笔记本电脑", 9999.99);
System.out.println("Product: " + product);
System.out.println("是否昂贵: " + product.isExpensive());
// 4. 验证不可变性
System.out.println("\n=== 验证不可变性 ===");
testImmutability(person, employee, product);
}
private static void testImmutability(Person person, Employee employee, Product product) {
// 检查类是否是final
System.out.println("Person类是否final: " + Character.isUpperCase(
Person.class.getModifiers() & 16 // 16 = final modifier
));
// 尝试各种修改方式(编译错误注释掉)
// person.name = "王五"; // 编译错误:无法赋值
// person.age = 30; // 编译错误:无法赋值
// employee.getSkills().add("Go"); // 运行错误:UnsupportedOperationException
// product.setName("新名字"); // 编译错误:没有setter
}
}
不可变类的线程安全验证
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 不可变类天然线程安全
*/
public class ImmutableThreadSafetyDemo {
public static void main(String[] args) throws InterruptedException {
final int threadCount = 100;
final CountDownLatch ready = new CountDownLatch(threadCount);
final CountDownLatch start = new CountDownLatch(1);
final CountDownLatch done = new CountDownLatch(threadCount);
ExecutorService pool = Executors.newFixedThreadPool(threadCount);
// 多个线程共享同一个不可变对象
Person sharedPerson = new Person("共享", 30, new Date());
for (int i = 0; i < threadCount; i++) {
final int id = i;
pool.submit(() -> {
try {
ready.countDown();
start.await();
// 并发读取不可变对象
for (int j = 0; j < 1000; j++) {
System.out.println("线程" + id + ": " + sharedPerson.getName()
+ ", " + sharedPerson.getAge());
// 不可变对象无需同步,不会出现竞态条件
}
done.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
ready.await();
System.out.println("所有线程就绪,开始并发访问...");
start.countDown();
done.await();
pool.shutdown();
System.out.println("所有线程完成,数据一致,无竞态问题");
}
}
- 遵守5条规则:final类、private final字段、无setter、构造器初始化所有字段、防御性拷贝
- 可变对象处理:使用防御性拷贝或返回不可修改视图
- 使用Builder模式:字段较多时提高可读性
- 考虑使用record:Java 14+简化不可变类的创建
- 实现equals和hashCode:基于不可变字段
- 文档说明:在类注释中说明是不可变类
- 性能考虑:过多的小对象创建可能影响性能,考虑缓存
不可变类在函数式编程、并发编程中有广泛的应用,是现代Java编程的重要技巧。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播