arraylist字段

bttbmeg0  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(259)

我目前正在学习初级java,在使用 ArrayList 在构造函数中用作参数时。
当我必须初始化 ArrayList 在类构造函数中,我通常编写如下内容(在本例中,假设我要创建 ArrayList 作为类字段的整数)。

public class Example {

    private ArrayList<Integer> myList;

    public Example(ArrayList<Integer> myInts){
        this.myList = myInts;
    }

}

但是,当我看到人们在教程或教科书中做同样的事情时,他们会编写以下代码:

public class Example {

    private ArrayList<Integer> myList;

    public Example(int myInts){
        this.myList = new ArrayList<>();
        addIntegers(myInts);
    }

    public void addIntegers(int myInts){
        this.myList.add(myInts);
    }

}

这两个例子有区别吗?我假设我的方法是错误的,但实际上运行两个版本会得到相同的结果(我的理解有限),所以我很难理解这两个变体的区别。

ao218c7q

ao218c7q1#

有区别,是的。在给出的代码中,可以这样调用构造函数:

ArrayList<Integer> values = new ArrayList<>(List.of(1, 2, 3, 4));
Example example = new Example(values);

在对象构造之后,调用方仍然可以访问 values ,即 example . 通过操纵这个数据结构,调用方可以 example 处于意料之外的状态并引起问题。
为了防止此类问题,我们通常不直接使用从外部传入的引用类型作为内部状态,而是生成它们的副本。本质上,这就是第二个例子所做的。如果我们还想通过 List 作为构造函数的参数,我们可以复制列表:

public class Example {

    private ArrayList<Integer> myList;

    public Example(Collection<Integer> myInts) {
        this.myList = new ArrayList<>(Objects.requireNonNull(myInts));
    }

    public Example(Integer... myInts) {
        this(Arrays.asList(Objects.requireNonNull(myInts)));
    }

    public Example(int... myInts) {
        this(Arrays.stream(Objects.requireNonNull(myInts))
                .boxed()
                .collect(Collectors.toList()));
    }           
}

如果呼叫方改变了 List 传递给构造函数的 Example -示例不受影响,因为它对原始列表的副本进行操作。
备注:如果列表类型是可变的,那么复制列表通常是不够的;我们必须深度复制列表(即创建每个列表条目的副本)。一般来说,这在java中是不可能的。

相关问题