属性封装需防御性复制以切断外部对内部状态的修改通道:构造器中对可变对象(数组、list、date、自定义类)必须深拷贝;getter返回时也须返回副本而非原始引用;字段应声明为private final,优先使用不可变类型。

属性封装时做防御性复制,不是为了“藏好数据”,而是切断外部对内部状态的修改通道。只要外部能拿到你字段的原始引用,就等于把控制权交出去了。
构造器里接收可变对象必须拷贝
外部传进来的数组、集合、日期等,不能直接赋值给 private 字段。
- 数组:用 Arrays.copyOf(arr, arr.length) 或 arr.clone(),别写
this.data = arr; - List:用 new ArrayList(src),而不是
this.items = src; - Date:用 new Date(date.getTime()),避免用已过时的
clone() - 自定义可变类(如 Person):在构造器中调用其拷贝构造器或
copy()方法,确保内部字段也隔离
getter 返回时也要隔离引用
返回内部字段不能图省事写 return this.list;,否则调用方一调 add() 或 clear(),你的私有状态就变了。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 元素是不可变类型(String、Integer、LocalDateTime):返回 new ArrayList(this.list) 或 Java 10+ 的 List.copyOf(this.list)
- 元素是可变对象:需深拷贝每个元素,例如
this.list.stream().map(Person::copy).collect(Collectors.toList()) - 数组字段:同样要 Arrays.copyOf(this.array, this.array.length),不能返回原引用
- 避免踩坑:
Collections.unmodifiableList(this.list)只防结构修改,不防元素内容被改,也不防原始集合从别处被污染
字段声明和类型选择要配合防护
光靠拷贝不够,设计上要减少可变点。
- 所有字段声明为 private final,杜绝后续赋值
- 优先用不可变类型:时间用 LocalDateTime 替代 Date,集合用 record + 不可变元素
- 自定义参数类尽量设计成不可变类:final 类、private final 字段、构造器初始化、无 setter、可变字段在构造时就拷贝
- 如果用了 record,注意它只保证引用不变,不保证内容不变——
record Config(String name, List<string> tags)</string>中的tags仍可能被外部修改,得在构造器里做new ArrayList(tags)
别依赖 final 或 unmodifiable 就以为安全
final 只锁住引用,不锁住对象内容;unmodifiable 只挡一层调用,不防底层共享。
- 一个
final List<person></person>,外部仍可通过list.get(0).setName("x")改变内部状态 -
Collections.unmodifiableList(new ArrayList(original))挡不住 original 被别人改,也挡不住 person 对象本身被改 - 真正安全的是:构造时拷贝 + getter 时再拷贝(或返回不可变副本)+ 字段类型选不可变
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










