我知道有像这样的包装器方法Collections#unmodifiableSet
和它的其他变体Collections#unmodifiableMap
,Collections#unmodifiableList
等等,这使得集合不可变,前提是客户端只通过这些方法返回的引用而不是直接访问集合。但它是否会阻止集合中的单个对象是不可变的?我可以使用标准 JDK 类而不是像 Google Guava 这样的 api 来实现相同的目标吗?
问问题
409 次
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
您要求的是const
Java 中的等价物。这是不可能的。多年来,许多用户(包括我自己)都要求将其作为对 Java 的增强。它被 Sun 关闭并拒绝了。
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070
如果你想这样做,你必须在你的对象中构建一个可变性标志(可能在构建时)。然后在每个 mutator 方法中,检查可变性标志。也许您可以使用诸如 CGLIB 之类的代理库来做一些更“花哨”的事情,但对于您想要实现的目标来说,它可能过于复杂。
于 2013-02-19T15:45:51.017 回答