Java10CopyOf工厂方法是否适合构造函数中的防御副本
当实现一个不可变类时,该类的聚合由提供给构造函数的Java10CopyOf工厂方法是否适合构造函数中的防御副本,java,collections,copy,immutability,Java,Collections,Copy,Immutability,当实现一个不可变类时,该类的聚合由提供给构造函数的集合初始化,构造函数必须创建集合的防御副本,以防止调用方随后对聚合进行变异 在Java 10之前,这将产生如下代码: class Thing { private final List<Widget> widgets; public Thing(List<Widget> widgets) { this.widgets = Collections.unmodifiableList(new Array
集合
初始化,构造函数必须创建集合
的防御副本,以防止调用方随后对聚合进行变异
在Java 10之前,这将产生如下代码:
class Thing
{
private final List<Widget> widgets;
public Thing(List<Widget> widgets) {
this.widgets = Collections.unmodifiableList(new ArrayList<>(widgets));
}
public List<Widget> getWidgets() {
return widgets;
}
}
class Thing
{
private final List<Widget> widgets;
public Thing(List<Widget> widgets) {
this.widgets = List.copyOf(widgets);
}
public List<Widget> getWidgets() {
return widgets;
}
}
我说的对吗?您可以安全地使用
List.copyOf
制作防御性拷贝,至少在JDK16上是这样。List.copyOf
的代码在ImmutableCollections
中调用此方法,该方法在特定情况下返回相同的列表-当列表已经是在以下情况之前生成的List.of
的列表实例时:
static <E> List<E> listCopy(Collection<? extends E> coll) {
if (coll instanceof List12 || (coll instanceof ListN && ! ((ListN<?>)coll).allowNulls)) {
return (List<E>)coll;
} else {
return (List<E>)List.of(coll.toArray()); // implicit nullcheck of coll
}
}
请参阅此测试程序的输出-列表。copyOf
对传入的参数创建一个正确的新副本,这些参数是从ArrayList
或集合派生的。不可修改的列表
,但如果列表是由List生成的,则不会创建副本。of/copyOf
方法:
public static void main(String[] args) {
var a = new ArrayList<String>();
a.add("ONE");
var b = Collections.unmodifiableList(a);
a.add("TWO");
var c = List.copyOf(b);
a.add("THREE");
var d = List.copyOf(c);
System.out.println("a="+a);
System.out.println("b="+b);
System.out.println("c="+c);
System.out.println("d="+d);
System.out.println("a == b "+(a == b));
System.out.println("b == c "+(b == c));
System.out.println("c == d "+(c == d));
}
我不知道上面的方法是否会在JDK10..15中产生不同的结果,因为我没有安装这些方法。设计意图和列表的实现。copyOf
和其他copyOf
方法完全按照您的意愿进行,应该适合制作防御性副本。这个想法是,List.copyOf
总是复制,除非它能证明不复制是安全的
列表中的其他上下文。copyOf
是:
按迭代顺序返回包含给定集合元素的。给定集合不能为null,并且它不能包含任何null元素。如果随后修改了给定集合,则返回的列表将不会反映此类修改
实施说明:
如果给定集合是,则调用copyOf通常不会创建副本
关键的断言是第一段中的最后一句话,这句话说如果参数随后被修改,那么修改不会出现在返回的列表中。也就是说,返回的列表在概念上始终是一个副本
还请注意,“不可修改列表”是指向列表规范特定部分的链接,其中描述了由List.of
、List.copyOf
和流的收集器.toUnmodifiableList
返回的列表实例
集合返回的实例。不可修改列表
在此定义中不是“不可修改列表”。相反,这是一个错误。如果有对支持集合的引用,并且该集合本身是可修改的,则此类视图明确允许修改支持集合
是的,“不可修改列表”和“不可修改视图”之间的区别令人困惑,但这是我们已经确定的。很抱歉有一种选择是“不变的”。但这是不准确的,因为这些实例实际上是可变的,所以我们避免了在这些情况下使用“不可变”
在任何情况下,实际行为都反映了本规范:
var list1 = new ArrayList<String>(Arrays.asList("a", "b", "c"))
var list2 = Collections.unmodifiableList(list1)
var list3 = List.copyOf(list2)
var list4 = List.copyOf(list3)
list2 == list3
==> false
list3 == list4
==> true
list1.add("d")
list2
==> [a, b, c, d]
list3
==> [a, b, c]
var list1=newarraylist(Arrays.asList(“a”、“b”、“c”))
var list2=集合。不可修改列表(list1)
var list3=List.copyOf(list2)
var list4=List.copyOf(list3)
list2==list3
==>错误
list3==list4
==>正确
清单1.添加(“d”)
清单2
==>[a、b、c、d]
清单3
==>[a、b、c]
换句话说,List.copyOf
确实是不可修改视图的防御副本,规范要求这种行为
a=[ONE, TWO, THREE]
b=[ONE, TWO, THREE]
c=[ONE, TWO]
d=[ONE, TWO]
a == b false
b == c false
c == d true
var list1 = new ArrayList<String>(Arrays.asList("a", "b", "c"))
var list2 = Collections.unmodifiableList(list1)
var list3 = List.copyOf(list2)
var list4 = List.copyOf(list3)
list2 == list3
==> false
list3 == list4
==> true
list1.add("d")
list2
==> [a, b, c, d]
list3
==> [a, b, c]