在 java 中防止外部修改集合类型字段,核心做法是在 getter 方法中返回该集合的不可变副本(如使用 collections.unmodifiablelist),并在 setter 或构造函数中对传入的外部集合进行防御性拷贝。这样外部代码获取到的是只读视图或独立副本,无法通过引用直接修改原对象的内部状态。

Getter 方法如何阻断外部修改
当外部调用者通过 Getter 获取集合时,如果直接返回内部字段的引用,外部代码持有该引用后就可以随意增删元素。为了防止这种情况,必须在 Getter 中返回一个包装后的不可变对象。例如使用 Collections.unmodifiableList 包裹原始列表,任何尝试修改该返回值的行为都会抛出 UnsupportedOperationException。这确保了外部只能读取数据,不能改变内部状态。

import java.util.*;
public class User {
private List<string> roles = new ArrayList();
public User() {}
// 防御性拷贝:防止外部传入的集合被后续修改影响内部状态
public void setRoles(List<string> roles) {
this.roles = new ArrayList(roles);
}
// 返回不可变视图:防止外部通过引用修改内部集合
public List<string> getRoles() {
return Collections.unmodifiableList(roles);
}
}
</string></string></string>
Setter 方法为何需要防御性拷贝
除了 Getter 的保护,Setter 方法同样关键。如果 Setter 直接赋值 this.roles = roles;,外部传入的集合与内部字段共享同一引用。外部随后对该集合的任何修改都会直接影响当前对象。因此,必须使用 new ArrayList(roles) 创建一个新的副本,切断与外部集合的联系。这样即使外部修改了原来的集合,当前对象的内部数据依然保持不变。

import java.util.*;
public class Order {
private List<string> items = new ArrayList();
public void setItems(List<string> items) {
// 防御性拷贝,确保内部状态不受外部集合后续变更的影响
this.items = new ArrayList(items);
}
public List<string> getItems() {
return Collections.unmodifiableList(items);
}
public static void main(String[] args) {
Order order = new Order();
List<string> externalList = new ArrayList();
externalList.add("Item A");
order.setItems(externalList);
// 外部修改原集合
externalList.add("Item B");
// 内部集合不受影响,仍只有 "Item A"
System.out.println(order.getItems());
}
}
</string></string></string></string>
基于程序运行结果的具体验证
在上述 Order 类的实现中,通过运行 main 方法可以明确看到防御性拷贝的效果。外部列表 externalList 在设置后追加了 "Item B",但调用 order.getItems() 返回的列表中仅包含 "Item A"。这证明了内部字段 items 是独立于外部输入的副本。同时,如果尝试对 getItems() 的返回值执行 add 操作,程序将抛出异常,从而双重保障了集合数据的完整性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











