java无原生readonly关键字,需通过private字段+public getter、不可变集合(如list.copyof)、防御性拷贝及record等组合策略实现只读暴露,核心是阻断所有修改路径。

Java 中没有原生的 readonly 关键字,但可以通过封装 + 不可变性 + 防御性拷贝等组合策略,安全地向外部暴露只读属性。核心原则是:**不让外部获得可修改的引用,也不提供修改入口。**
1. 使用 private 字段 + public getter(基础封装)
这是最常见也最必要的第一步:字段私有化,仅通过 getter 暴露访问能力。
⚠️ 注意:仅靠 getter 不足以保证“只读”,尤其对可变对象(如 ArrayList、HashMap)——返回原始引用会让调用方直接修改内部状态。
✅ 正确示例:
public class User {
private final String name; // 基本类型或不可变类(String/LocalDateTime等),final + private 即安全
private final List<string> roles; // 可变引用,需额外防护
public User(String name, List<string> roles) {
this.name = name;
// 防御性拷贝:不信任传入参数
this.roles = new ArrayList(Objects.requireNonNull(roles));
}
public String getName() {
return name; // 安全:String 不可变
}
public List<string> getRoles() {
return Collections.unmodifiableList(roles); // 返回只读视图,非原始引用
}
}</string></string></string>
2. 对集合类使用不可变包装或不可变实现
避免返回 new ArrayList(list) 这类可变副本(外部仍能改它),而应返回真正不可修改的视图或实例。
-
Collections.unmodifiableXXX():返回动态只读视图(底层变更仍可见,但禁止修改操作) -
List.copyOf()(Java 10+)、Set.copyOf()、Map.copyOf():返回不可变快照(推荐,线程安全且更明确) - Guava 的
ImmutableList.of()或ImmutableList.copyOf():功能更强,支持空值控制和构建器模式
✅ 推荐写法(Java 10+):
private final List<string> tags;
public User(List<string> tags) {
this.tags = List.copyOf(tags); // 创建不可变副本,null 安全需自行校验
}
public List<string> getTags() {
return tags; // 直接返回,已是不可变
}</string></string></string>
3. 对自定义可变对象做防御性拷贝
如果属性是自定义的可变类(如 Address),不能只返回引用,也不能只套 unmodifiableList——必须深拷贝或返回不可变版本。
✅ 建议方式:
- 让
Address类自身设计为不可变(所有字段final,无 setter,构造即完整) - 若无法改造,getter 中返回新实例:
return new Address(this.address); - 或提供
toImmutable()方法,在 getter 中调用
例如:
public class UserProfile {
private final Address homeAddress;
public UserProfile(Address homeAddress) {
this.homeAddress = Objects.requireNonNull(homeAddress).immutableCopy();
}
public Address getHomeAddress() {
return homeAddress; // 已是不可变实例
}
}
4. 使用 record(Java 14+)简化不可变数据载体
对于纯数据类,record 是最简洁安全的选择:自动 final 字段、不可变、自动实现 equals/hashCode/toString,且构造后无法修改。
✅ 示例:
public record Product(String name, BigDecimal price, List<string> categories) {
// categories 是可变引用,仍需防护
public List<string> categories() {
return List.copyOf(categories);
}
}</string></string>
注意:record 的组件仍是公开的(隐式 public accessor),所以集合类仍要像上面一样做不可变返回。
关键不在“有没有 readonly”,而在“是否切断了所有修改路径”。只要字段私有、引用不外泄、可变对象被隔离或冻结,外部就无法安全地破坏内部状态。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











