3

我正在实现一个不可变类,其结构如下:

public final class A{
    private final B bOb;
    public A(){
        bOb = new B();
    }
    public A(A a){
        bOb = new B(a.bOb);
    }
    public A addData(Type data){ // Type - Integer,String,char,etc.
        A newA = new A(this); //making a copy of the object that is calling addData method
        newA.bOb.add(data);
        return newA;
    }
}

这个实现正确吗?假设对象 bOb 是一个列表。

4

5 回答 5

2

您的实施:

public A addData(int data){
    A newA = new A(this);
    newA.bOb.add(data); // <--- bOb is mutable
    return newA;
}

一个 bOb 正在被更改,因此如果您公开对 bOb 的任何直接访问,它可以被更改。(因为你没有暴露任何关于 bOb 的信息,所以这个场景没有意义。)

提示:

  • Collections.emptyList()返回一个不可变的列表。
  • Collections.unmodifiableList()返回给定列表的不可变浅拷贝。

考虑这个“更安全”的实现:

import java.util.*;

public final class A<T>{ //T must also be immutable (String, integer, char, ...)
    private final List<T> list;
    public A(){
        this.list = Collections.emptyList();
    }
    public A(List<T> list){
        this.list = Collections.unmodifiableList(list);
    }
    public A<T> addData(T data){
        List<T> shallowCopy = new ArrayList<T>(this.list);
        shallowCopy.add(data);
        return new A<T>(shallowCopy);
    }
    public List<T> getItems() {
        return this.list;
    }
}
于 2012-08-23T09:48:48.243 回答
2

它不是完全不可变的,因为 B 本身似乎是可变的(通过 add 方法)并且 A 包含 B 的实例。

但是,我认为它实际上是不可变的(即,从外部观察者的角度来看,它的行为就好像它是不可变的),前提是以下所有条件都是正确的:

  • new B(B)执行完整的深层副本B(如果不是,则addData可能会改变原始内容中的某些内容B
  • 您没有bOb通过任何其他方式泄露对
  • 添加的元素本身是不可变的

您可以从有效地不可变中获得不可变性的大部分好处,所以我认为这种设计是可以的,只要Type它是不可变的 - 在构造过程中改变一个对象是可以的,前提是在您将引用传递给其他人之后它永远不会改变。一个很好的例子是java.lang.String- 在内部它包含一个可变数组,该数组在构造 String 时写入,但在那之后从未更改。

于 2012-08-23T09:49:35.080 回答
1

如果bOb是一个列表并且它包含可变内容,那么不是。但似乎您仅用int作内容,这解决了问题。

于 2012-08-23T09:47:05.990 回答
1

在这种形式下,是的,你的类是不可变的。

但是,这是一个微不足道的示例,实际上对任何事情都没有用,因为您无法访问任何内部数据。您需要注意的是不要让任何引用bObA. 如果添加返回的方法bOb,则需要返回 的副本bOb以避免意外允许调用者更改 . 的任何内容A

于 2012-08-23T09:47:42.933 回答
0

这取决于B(B b)构造函数的工作方式。如果它是一个复制构造函数,它应该对b字段进行深层复制。在这种情况下A是不可变的。

相反,如果构造函数只是简单地引用同一个b实例,对它的任何更改都会反映在bOb属性上,所以A类不是不可变的......

于 2012-08-23T10:22:31.467 回答