如何创建深度不可修改的集合?

时间:2009-01-06 09:55:37

标签: java unmodifiable

在从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对象。

有什么想法吗?

6 个答案:

答案 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,有这个库:

http://code.google.com/p/pcollections/

答案 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公开列表的方法,并确保列表不会被修改。