Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/395.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_Immutability_Defensive Copy - Fatal编程技术网

Java 关于不可变的类

Java 关于不可变的类,java,immutability,defensive-copy,Java,Immutability,Defensive Copy,我有一个关于创建不可变类的问题。以下是我考虑的几点: 期末考试 使所有成员为最终成员,在静态块或构造函数中显式设置它们 将所有成员保密 没有修改状态的方法 要非常小心地限制对可变成员组件的访问(记住字段可能是final,但对象仍然可以是可变的。即private final Date imStillMutable)-有关更多信息,请参阅防御性复制或其同类复制构造函数 但是我根本不理解5点,你能告诉我或给我一个例子,在这个例子中5点是清楚的吗?final表示指针不能指向另一个引用。 例如: fin

我有一个关于创建不可变类的问题。以下是我考虑的几点:

  • 期末考试
  • 使所有成员为最终成员,在静态块或构造函数中显式设置它们
  • 将所有成员保密
  • 没有修改状态的方法
  • 要非常小心地限制对可变成员组件的访问(记住字段可能是final,但对象仍然可以是可变的。即private final Date imStillMutable)-有关更多信息,请参阅防御性复制或其同类复制构造函数


  • 但是我根本不理解5点,你能告诉我或给我一个例子,在这个例子中5点是清楚的吗?

    final
    表示指针不能指向另一个引用。 例如:

    final Object obj = new Object();
    obj = new Object(); //Invalid
    
    public final class Foo
    {
        private final List<String> strings;
    
        public Foo(List<String> strings)
        {
            // Defensive copy on construction. Protects from constructing
            // code mutating the list.
            this.strings = new ArrayList<String>(strings);
        }
    
        public List<String> getStrings()
        {
            // Defensive copy on read. Protects from clients mutating the list.
            return new ArrayList<String>(strings);
        }
    }
    
    但是
    final
    不会阻止修改对象:

    obj.setWhatever("aaa"); //Perfectly valid
    
    如果您没有限制对成员的访问,那么任何人都可以获取该对象并对其进行修改

    例如:
    yourClass.getObject().setWhatever(“aaa”)。


    防御性复制意味着
    getObject()
    不会直接返回该对象,但它会复制该对象,然后返回该对象。这样,如果调用方修改了返回的对象,它就不会修改类的原始成员。

    第5点建议,任何时候如果有任何方法返回与可变对象有关的内容,您都希望创建一个独立于私有状态的副本。例如:

    final Object obj = new Object();
    obj = new Object(); //Invalid
    
    public final class Foo
    {
        private final List<String> strings;
    
        public Foo(List<String> strings)
        {
            // Defensive copy on construction. Protects from constructing
            // code mutating the list.
            this.strings = new ArrayList<String>(strings);
        }
    
        public List<String> getStrings()
        {
            // Defensive copy on read. Protects from clients mutating the list.
            return new ArrayList<String>(strings);
        }
    }
    
    公共最终课程Foo
    {
    私有最终列表字符串;
    公共Foo(列表字符串)
    {
    //防御性建筑复制。防止建筑
    //修改列表的代码。
    this.strings=新的ArrayList(字符串);
    }
    公共列表getStrings()
    {
    //防御性读取拷贝。防止客户端更改列表。
    返回新的ArrayList(字符串);
    }
    }
    
    注意,只有当状态是可变的时,才需要防御性复制。例如,如果在上述类中使用
    ImmutableList
    (例如来自Guava)作为状态,则需要在构造时创建一个新列表(除非输入也是
    ImmutableList
    ),而不是在
    getStrings


    还要注意,在这种情况下,
    String
    是不可变的,因此我们不需要复制每个字符串。如果这是一个
    列表
    ,我们需要创建一个新列表和每个元素的一个新副本,作为防御副本的一部分。正如你所看到的,当你所有的状态都是不变的时,生活就会变得简单。

    我在搜索这个话题时偶然发现了这个答案。当列表中的X对象不受我们控制,并且是可变的,并且不提供可靠的克隆方法时,该怎么办?@Jitendra:这取决于上下文。也许您正处于这样一种情况,您可以相信其他代码不会更改值。。。或者,您可能需要自己有效地克隆这些值。这里没有唯一正确的答案。