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

在从getter方法返回之前,我经常使集合字段不可修改:

private List _xs; .... List getXs(){ return Collections.unmodifiableList(_xs); } 

但是,如果上面的X本身就是一个List,我想不出一个方便的方法:

 private List<List> _yLists; ..... List<List> getYLists() { return Collections.unmodifiableList(_yLists); } 

上面的问题当然是虽然客户端无法修改列表列表,但它可以从嵌入列表中添加/删除Y对象。

有什么想法吗?

我能想到的最好用的是来自Google Collections的ForwardingList 。 欢迎评论。

 private static  List> unmodifiableList2(final List> input) { return Collections.unmodifiableList(new ForwardingList>() { @Override protected List> delegate() { return Collections.unmodifiableList(input); } @Override public List get(int index) { return Collections.unmodifiableList(delegate().get(index)); } }); } 

不幸的是,没有简单的方法可以在java中获得深度的持久性。 你必须通过始终确保列表中的列表也是不可修改的来破解它。

我也有兴趣知道任何优雅的解决方案。

clojure集合(map,set,list,vector)都可以嵌套,默认情况下是不可变的。 对于纯java,有这个库:

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

如果您查看Collections.unmodifiable *(…)方法的实现,您可以看到它们只是包装集合。 以同样的方式做一个深层实用工具应该是可行的。

这样做的缺点是它会为集合访问添加额外的方法调用,从而影响性能。

如果您的唯一目标是强制封装,那么经典的解决方案是使用clone()或类似方法返回不是对象内部状态的结构。 这显然只有在克隆所有对象并且复制的结构足够小时才有效。

如果这是一个相当常用的数据结构,另一个选项是使访问它的API更具体,这样您就可以更详细地控制特定的调用。 编写自己的List实现,如上所述是一种方法,但如果您可以缩小对特定用例的调用范围,则可以公开特定的访问API而不是List接口。

以防有人对此感兴趣是一个简单的解决方案:

  public List> toUnmodifiable(List> nestedList) { List> listWithUnmodifiableLists = new ArrayList<>(); for (List list : nestedList) { listWithUnmodifiableLists .add(Collections.unmodifiableList(list)); } return Collections.unmodifiableList(listWithUnmodifiableLists); } 

这可以用作示例,如果您想要使用getList()方法公开列表,则可以返回:toUnmodifiable(mNestedList),其中mNestedList是类中的私有列表。

我个人认为在实现用于在Android中使用GSON进行解析的类时非常有用,因为能够修改响应没有意义,在这种情况下是反序列化的json,我使用此方法作为一种公开方式带有getter的列表,并确保列表不会被修改。