在从getter方法返回之前,我经常使集合字段不可修改:
private List<X> _xs;
....
List<X> getXs(){
return Collections.unmodifiableList(_xs);
}
但如果上面的X本身就是一个List,那么我想不出一个方便的方法:
private List<List<Y>> _yLists;
.....
List<List<Y>> getYLists() {
return Collections.unmodifiableList(_yLists);
}
上述问题当然是虽然客户端无法修改列表列表,但它可以从嵌入列表中添加/删除Y对象。
有什么想法吗?
答案 0 :(得分:7)
我能想出的最好用ForwardingList from Google Collections。欢迎提出意见。
private static <T> List<List<T>> unmodifiableList2(final List<List<T>> input) {
return Collections.unmodifiableList(new ForwardingList<List<T>>() {
@Override protected List<List<T>> delegate() {
return Collections.unmodifiableList(input);
}
@Override public List<T> get(int index) {
return Collections.unmodifiableList(delegate().get(index));
}
});
}
答案 1 :(得分:3)
不幸的是,没有简单的方法可以在java中获得深度的持久性。你必须通过始终确保列表中的列表也是不可修改的来破解它。
我也有兴趣知道任何优雅的解决方案。
答案 2 :(得分:2)
clojure集合(map,set,list,vector)都可以嵌套,默认情况下是不可变的。对于纯java,有这个库:
答案 3 :(得分:0)
如果查看Collections.unmodifiable *(...)方法的实现,可以看到它们只是包装集合。以同样的方式做一个深层实用工具应该是可行的。
这样做的缺点是它会对集合访问添加额外的方法调用,从而影响性能。
答案 4 :(得分:0)
如果您的唯一目标是强制执行封装,那么经典的解决方案是使用clone()或类似方法返回不是对象内部状态的结构。这显然只有在克隆所有对象并且复制的结构足够小时才有效。
如果这是一个相当常用的数据结构,另一个选项是使访问它的API更加具体,这样您就可以对特定的调用进行更详细的控制。编写自己的List实现,如上所述是一种方式,但如果您可以缩小对特定用例的调用范围,则可以公开特定的访问API而不是List接口。
答案 5 :(得分:0)
以防有人对此感兴趣是一个简单的解决方案:
public List<List<Double>> toUnmodifiable(List<List<Double>> nestedList) {
List<List<Double>> listWithUnmodifiableLists = new ArrayList<>();
for (List<Double> list : nestedList) {
listWithUnmodifiableLists
.add(Collections.unmodifiableList(list));
}
return Collections.unmodifiableList(listWithUnmodifiableLists);
}
如果您想要使用getList()方法公开列表,可以使用它作为解决方案,您可以返回:toUnmodifiable(mNestedList),其中mNestedList是类中的私有列表。
我个人认为在实现用于在Android中使用GSON进行解析的类时非常有用,因为能够修改响应没有意义,在这种情况下是反序列化的json,我使用了这种方法作为使用getter公开列表的方法,并确保列表不会被修改。