2

我知道有像这样的包装器方法Collections#unmodifiableSet和它的其他变体Collections#unmodifiableMapCollections#unmodifiableList等等,这使得集合不可变,前提是客户端只通过这些方法返回的引用而不是直接访问集合。但它是否会阻止集合中的单个对象是不可变的?我可以使用标准 JDK 类而不是像 Google Guava 这样的 api 来实现相同的目标吗?

4

4 回答 4

2

不,您必须使自己的类成为不可变版本。

样本 :

List< StringBuilder > l1 = new LinkedList< StringBuilder >();
l1.add( new StringBuilder()); // ok
List< StringBuilder > l2 = Collections.unmodiableList( l1 );
l2.get(0).append( "Hello" );  // ok, because StringBuilder, unlike String is mutable
l2.add( new StringBuilder()); // throws exception
于 2013-02-19T15:15:11.970 回答
0

我能想到的让一个类不可变的唯一方法是把它包装在一个代理中——然后你可以访问控制任何变异方法:

IE。

MyClass {
  private int anInt;

  public void setInt(int a) {
      anInt = a;
  }
  public int getInt() {
      return anInt;
  }
  ...

进而

MyProxy {
  private MyClass myClass = ...;

  public int getInt() {
      return myClass.getInt();
  }
  ...

等等。

您也可以通过反射来实现相同的目的(以同样的方式 Spring 包装 bean,您通常只与它们的代理交互)

不过,如果客户掌握了实际的底层类(本例中为 MyClass),那么他们将能够改变内部。没有真正的方法可以直接阻止这种情况,除了只公开你让客户看到的“可变”包装器

于 2013-02-19T15:17:30.190 回答
0

如果我理解你的目标。你可以使用这样的东西

class Wraper<T>{
    List<T> list = new ArrayList<T>(); //Other Collection?
    T someObj = getYourInstance();
    public T get(int index) {
        T obj = list.get(index);
        if (obj.equals(someObj)){//should be overriden
           return createInstanceOf(obj);
        } else {
           return obj;
        }
    }
}
于 2013-02-19T15:41:04.600 回答
0

您要求的是constJava 中的等价物。这是不可能的。多年来,许多用户(包括我自己)都要求将其作为对 Java 的增强。它被 Sun 关闭并拒绝了。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070

如果你想这样做,你必须在你的对象中构建一个可变性标志(可能在构建时)。然后在每个 mutator 方法中,检查可变性标志。也许您可以使用诸如 CGLIB 之类的代理库来做一些更“花哨”的事情,但对于您想要实现的目标来说,它可能过于复杂。

于 2013-02-19T15:45:51.017 回答