当你写一个构造函数(或任何方法),它接收一个可变对象(Mutable Object)作为参数,并且要把这个对象存下来作为你类的一部分(即存入一个字段/成员变量),你就必须创建它的防御性拷贝(Defensive Copy)。
在考试时,看到一个构造函数,问自己这两个问题:

  1. 参数是不是一个“盒子”?

    • 参数的类型是不是一个可以被修改的集合(如 CollectionListArrayListMapHashMap)或者其他可变对象(如 DateStringBuilder)?
    • 原始类型intdoubleboolean)和不可变类型StringInteger不算。它们天生是安全的。
    • 在你的代码 public CombinedPolicy(Collection<...> policies) 中,Collection 就是一个“盒子”,所以第一个问题的答案是**“是”**。
  2. 我是不是要把这个“盒子”存起来以后用?

    • 你是不是在构造函数里写了 this.fieldName = aParameter 这样的代码?
    • 在你的代码 this.policies = List.copyOf(policies); 中,你显然是要把这个 policies 集合存到 this.policies 字段里,供以后(比如 traversable() 方法)使用。所以第二个问题的答案也是**“是”**。

如果两个问题的答案都是“是”,那么你就必须使用 List.copyOf(或 Map.copyOf 等)或者 new ArrayList<>(...) 这样的方式来创建一个副本。


为了防止创建你对象的“客户”代码,在创建完对象之后,还能偷偷修改你对象内部的状态。

List.copyOf 是最好的选择,因为它不仅创建了副本,还保证了你内部的这份副本是不可修改的,提供了双重保险。

简单总结: 在构造函数里,凡是要存起来的、可变的参数,都要复制一份。这应该成为你的肌肉记忆。