Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java10CopyOf工厂方法是否适合构造函数中的防御副本_Java_Collections_Copy_Immutability - Fatal编程技术网

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]