Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.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
Java ';集合。不可修改的集合';在构造函数中_Java_Constructor_Defensive Copy - Fatal编程技术网

Java ';集合。不可修改的集合';在构造函数中

Java ';集合。不可修改的集合';在构造函数中,java,constructor,defensive-copy,Java,Constructor,Defensive Copy,在代码审查期间,我不时看到这样的构造函数: Foo(Collection<String> words) { this.words = Collections.unmodifiableCollection(words); } Foo(集合词){ this.words=Collections.unmodifiableCollection(words); } 这是保护类的内部状态的正确方法吗?如果不是,那么在构造函数中创建适当的防御副本的惯用方法是什么?应该是这样,但这是不正确

在代码审查期间,我不时看到这样的构造函数:

Foo(Collection<String> words) {
    this.words = Collections.unmodifiableCollection(words);
}
Foo(集合词){
this.words=Collections.unmodifiableCollection(words);
}

这是保护类的内部状态的正确方法吗?如果不是,那么在构造函数中创建适当的防御副本的惯用方法是什么?

应该是这样,但这是不正确的,因为调用者仍然可以修改基础列表

不要包装清单,你应该做一份防御性的复制品,例如用番石榴代替

Foo(集合词){
if(words==null){
抛出新的NullPointerException(“单词不能为null”);
}
this.words=ImmutableList.copyOf(words);
if(this.words.isEmpty()){//示例额外前提条件
抛出新的IllegalArgumentException(“单词不能为空”);
}
}
因此,为类建立初始状态的正确方法是:

  • 检查输入参数的
    null
  • 如果不能保证输入类型是不可变的(如
    集合
    的情况),则制作一份防御性副本。在这种情况下,因为元素类型是不可变的(
    String
    ),所以可以使用浅拷贝,但如果不是,则必须创建更深的拷贝
  • 对副本执行任何进一步的前提条件检查。(在原版上执行此操作可能会使您受到攻击。)

  • 应该是,但它不正确,因为调用方仍然可以修改基础列表

    不要包装清单,你应该做一份防御性的复制品,例如用番石榴代替

    Foo(集合词){
    if(words==null){
    抛出新的NullPointerException(“单词不能为null”);
    }
    this.words=ImmutableList.copyOf(words);
    if(this.words.isEmpty()){//示例额外前提条件
    抛出新的IllegalArgumentException(“单词不能为空”);
    }
    }
    
    因此,为类建立初始状态的正确方法是:

  • 检查输入参数的
    null
  • 如果不能保证输入类型是不可变的(如
    集合
    的情况),则制作一份防御性副本。在这种情况下,因为元素类型是不可变的(
    String
    ),所以可以使用浅拷贝,但如果不是,则必须创建更深的拷贝
  • 对副本执行任何进一步的前提条件检查。(在原版上执行此操作可能会使您受到攻击。)
  • 只创建包装器,通过它您不能修改
    单词
    ,但这并不意味着
    单词
    不能在其他地方修改。例如:

    List<String> words = new ArrayList<>();
    words.add("foo");
    Collection<String> fixed = Collections.unmodifiableCollection(words);
    
    System.out.println(fixed);
    words.add("bar");
    System.out.println(fixed);
    
    如果要在不可修改集合中保留
    单词的当前状态,则需要从传递的集合中创建自己的元素副本,然后用
    集合将其包装。不可修改集合(WordScope)

    例如,如果您只想保留单词的顺序:

    this.words = Collections.unmodifiableCollection(new ArrayList<>(words));
    // separate list holding current words ---------^^^^^^^^^^^^^^^^^^^^^^
    
    this.words=Collections.unmodifiableCollection(新的ArrayList(words));
    //包含当前单词的单独列表---------^^^^^^^^^^^^^^^^^^^^^^
    
    只创建包装器,通过它您不能修改
    单词
    ,但这并不意味着
    单词
    不能在其他地方修改。例如:

    List<String> words = new ArrayList<>();
    words.add("foo");
    Collection<String> fixed = Collections.unmodifiableCollection(words);
    
    System.out.println(fixed);
    words.add("bar");
    System.out.println(fixed);
    
    如果要在不可修改集合中保留
    单词的当前状态,则需要从传递的集合中创建自己的元素副本,然后用
    集合将其包装。不可修改集合(WordScope)

    例如,如果您只想保留单词的顺序:

    this.words = Collections.unmodifiableCollection(new ArrayList<>(words));
    // separate list holding current words ---------^^^^^^^^^^^^^^^^^^^^^^
    
    this.words=Collections.unmodifiableCollection(新的ArrayList(words));
    //包含当前单词的单独列表---------^^^^^^^^^^^^^^^^^^^^^^
    
    不,这并不能完全保护它

    我喜欢用这个成语来确保内容是不变的:

    public Breaker(Collection<String> words) {
        this.words = Collections.unmodifiableCollection(
            Arrays.asList(
                words.toArray(
                    new String[words.size()]
                )
            )
        );
    }
    
    公共断路器(集合字){
    this.words=Collections.unmodifiableCollection(
    Arrays.asList(
    托雷(
    新字符串[words.size()]
    )
    )
    );
    }
    

    但这里的缺点是,如果传入哈希集或树集,它将丢失速度查找。如果您关心哈希或树的特性,您可以做一些事情,而不是将其转换为固定大小的列表。

    不,这并不能完全保护它

    我喜欢用这个成语来确保内容是不变的:

    public Breaker(Collection<String> words) {
        this.words = Collections.unmodifiableCollection(
            Arrays.asList(
                words.toArray(
                    new String[words.size()]
                )
            )
        );
    }
    
    公共断路器(集合字){
    this.words=Collections.unmodifiableCollection(
    Arrays.asList(
    托雷(
    新字符串[words.size()]
    )
    )
    );
    }
    

    但这里的缺点是,如果传入哈希集或树集,它将丢失速度查找。如果您关心哈希或树特征,您可以做一些事情,而不是将其转换为固定大小的列表。

    我只是
    集合
    ,不一定这是一个
    列表
    @MichalKordas您仍然可以将其视为
    集合
    ,应该没有区别。如果确实如此,那么首先接受任何收藏都是错误的。@MichalKordas:这并没有改变biziclop的观点<代码>集合。不可修改的集合
    仅包装现有集合。。。如果调用方可以修改该集合,那么您仍然没有真正保护类的内部状态。我只有
    集合
    ,不一定这是一个
    列表
    @MichalKordas。您仍然可以将其视为
    集合
    ,这应该没有什么区别。如果确实如此,那么首先接受任何收藏都是错误的。@MichalKordas:这并没有改变biziclop的观点<代码>集合。不可修改的集合
    仅包装现有集合。。。如果调用方可以修改该集合,那么您仍然没有真正保护类的内部状态。您能否建议
    集合的惯用构造函数应该是什么样子