今天为大家带来的是并发设计模式实战系列,第十二章不变模式(Immutable Object),废话不多说直接开始~
┌───────────────────┐ ┌───────────────────┐
│ Mutable State │ │ Immutable Object │
│ │ │ │
│ - 可修改字段 │──克隆─>│ - final字段 │
│ - setter方法 │ │ - 无修改方法 │
└───────────────────┘ └───────────────────┘
// 典型不可变类示例
public final class ImmutablePoint {
private final int x;
private final int y;
// 唯一初始化机会
public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
// 只有getter没有setter
public int getX() { return x; }
public int getY() { return y; }
}
系统组件 | 现实类比 | 核心特性 |
---|---|---|
可变对象 | 实验室中的文物 | 可修复、可清洁、需严格保护 |
不可变对象 | 展出的文物复制品 | 观众任意观察,无需防护措施 |
构造函数 | 3D扫描复制过程 | 一次性完成精确复制 |
import java.util.*;
// 深度不可变类示例
public final class ImmutablePerson {
private final String name;
private final int age;
private final List<String> hobbies;
private final Date birthDate;
// 防御性拷贝构造函数
public ImmutablePerson(String name, int age, List<String> hobbies, Date birthDate) {
this.name = name;
this.age = age;
this.hobbies = Collections.unmodifiableList(new ArrayList<>(hobbies));
this.birthDate = new Date(birthDate.getTime()); // Date是可变的,必须拷贝
}
// 只有getter方法
public String getName() { return name; }
public int getAge() { return age; }
// 返回不可修改视图
public List<String> getHobbies() {
return hobbies;
}
// 返回防御性拷贝
public Date getBirthDate() {
return new Date(birthDate.getTime());
}
@Override
public String toString() {
return "Person[name=" + name + ", age=" + age +
", hobbies=" + hobbies + ", birth=" + birthDate + "]";
}
public static void main(String[] args) {
List<String> hobbies = Arrays.asList("Reading", "Hiking");
Date birth = new Date(90, 5, 15); // 1990-06-15
ImmutablePerson person = new ImmutablePerson("Alice", 30, hobbies, birth);
// 尝试修改原始数据
hobbies.set(0, "Gaming");
birth.setYear(95);
System.out.println(person); // 输出显示不受影响
}
}
// 1. 防御性拷贝(针对可变字段)
this.hobbies = new ArrayList<>(hobbies);
// 2. 不可修改视图
Collections.unmodifiableList(hobbies);
// 3. 深拷贝日期类
this.birthDate = new Date(birthDate.getTime());
// 4. final类禁止继承
public final class ImmutablePerson {...}
方案 | 线程安全原理 | 性能开销 | 适用场景 |
---|---|---|---|
synchronized | 互斥访问 | 高 | 高竞争写操作 |
volatile | 可见性保证 | 低 | 单一状态变更 |
Immutable Object | 无状态变化 | 无 | 高频读取、配置类数据 |
CopyOnWrite | 写时复制 | 中 | 读多写少集合 |
类名 | 可变字段处理方式 | 典型用途 |
---|---|---|
String | 内部char数组为final | 文本处理 |
Integer | final int value | 数值包装 |
LocalDateTime | 所有字段final | 日期时间处理 |
Collections.emptyList() | 无修改方法 | 空集合占位 |
// 缓存常用实例(如IntegerCache)
private static final ImmutablePerson DEFAULT_USER =
new ImmutablePerson("Guest", 0, List.of(), new Date(0));
public static ImmutablePerson defaultUser() {
return DEFAULT_USER; // 所有线程共享同一个安全实例
}
// 解决构造函数参数过多问题
public static class Builder {
private String name;
private int age;
// ...其他字段
public ImmutablePerson build() {
return new ImmutablePerson(name, age, hobbies, birthDate);
}
}
// Java 9的工厂方法创建不可变集合
List<String> hobbies = List.of("Reading", "Hiking");
// Guava的不可变集合
ImmutableList<String> hobbies =
ImmutableList.<String>builder().add("Reading").add("Hiking").build();
通过这种原理剖析+生活类比+生产代码+横向对比的解析方式,可以全面掌握不可变对象模式的设计精髓,并能在实际项目中正确应用。
好的!我们继续扩展内容,序号从 六 开始,深入探讨不可变对象模式的高级特性和工程实践:
// 表面不可变但实际可变的危险案例
public final class DangerousImmutable {
private final Date date; // Date本身是可变的
public DangerousImmutable(Date date) {
this.date = date; // 错误:未做防御性拷贝
}
public Date getDate() {
return date; // 错误:直接返回可变引用
}
}
// 攻击方式:
DangerousImmutable obj = new DangerousImmutable(new Date());
obj.getDate().setYear(2025); // 成功修改"不可变"对象
解决方案:
new Date(date.getTime())
)// 缓存常用值对象(适用于小而高频创建的对象)
public class ImmutablePoint {
private static final Map<String, ImmutablePoint> CACHE = new ConcurrentHashMap<>();
public static ImmutablePoint valueOf(int x, int y) {
String key = x + "," + y;
return CACHE.computeIfAbsent(key, k -> new ImmutablePoint(x, y));
}
// ...原有实现
}
// 适用于重hashCode()的对象
private volatile int hashCode; // 注意用volatile保证可见性
@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 31 * result + x;
result = 31 * result + y;
hashCode = result;
}
return hashCode;
}
// 部分字段可变的"半不可变"设计(需线程安全)
public class SemiImmutable {
private final String id; // 永久不可变
private volatile int counter; // 可变但线程安全
public SemiImmutable(String id) {
this.id = id;
}
// 仅允许原子更新
public void increment() {
counter++;
}
}
适用场景: 需要跟踪对象访问次数但核心ID不变的场景
// 解决多参数构造问题(带校验)
public class ImmutableConfig {
private final String host;
private final int port;
// ...其他字段
public static class Builder {
private String host;
private int port;
public Builder host(String host) {
if (!host.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) {
throw new IllegalArgumentException("Invalid host");
}
this.host = host;
return this;
}
public ImmutableConfig build() {
return new ImmutableConfig(this);
}
}
private ImmutableConfig(Builder builder) {
this.host = builder.host;
this.port = builder.port;
}
}
// 状态变更时生成新对象并通知观察者
public class ImmutableSensorData {
private final double value;
private final List<Consumer<ImmutableSensorData>> listeners = new CopyOnWriteArrayList<>();
public ImmutableSensorData update(double newValue) {
ImmutableSensorData newData = new ImmutableSensorData(newValue);
listeners.forEach(l -> l.accept(newData));
return newData;
}
public void addListener(Consumer<ImmutableSensorData> listener) {
listeners.add(listener);
}
}
List<ImmutablePerson> people = List.of(
new ImmutablePerson("Alice", 30),
new ImmutablePerson("Bob", 25)
);
// 纯函数式处理
List<String> names = people.stream()
.filter(p -> p.getAge() > 28)
.map(ImmutablePerson::getName)
.collect(Collectors.toUnmodifiableList());
反模式 | 问题描述 | 正确做法 |
---|---|---|
返回可变对象引用 | 外部可修改内部状态 | 返回防御性拷贝 |
继承不可变类 | 子类可能破坏不可变性 | 使用final类 |
构造函数参数校验缺失 | 可能构造出无效对象 | 构造时严格校验 |
// Java 14+ record自动实现不可变
public record ImmutablePoint(int x, int y) {
// 编译器自动生成:
// 1. final字段
// 2. 规范构造函数
// 3. equals/hashCode/toString
}
// 使用示例
ImmutablePoint p = new ImmutablePoint(10, 20);
System.out.println(p.x()); // 自动生成访问方法
Java版本 | 特性 | 示例 |
---|---|---|
Java 8 | Collections.unmodifiableX | Collections.unmodifiableList(list) |
Java 9 | List/Set/Map.of | List.of("a", "b") |
Java 10 | Collectors.toUnmodifiable | stream.collect(Collectors.toUnmodifiableList()) |
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有