代码之家  ›  专栏  ›  技术社区  ›  Miserable Variable

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

  •  15
  • Miserable Variable  · 技术社区  · 16 年前

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

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

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

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

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

    有什么想法吗?

    6 回复  |  直到 16 年前
        1
  •  7
  •   Miserable Variable    16 年前

    我能想到的最好的用途 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));
            }
        });
    }
    
        2
  •  3
  •   Chii    16 年前

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

    我也很想知道任何优雅的解决方案。

        3
  •  2
  •   Arthur Edelstein    13 年前

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

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

        4
  •  0
  •   iny    16 年前

    如果你看看Collections.unmobility*(…)方法的实现,你可以看到它们只是包装了集合。以同样的方式做一个深度实用程序应该是可行的。

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

        5
  •  0
  •   TREE    16 年前

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

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

        6
  •  0
  •   Ludvig W    8 年前

    如果有人对此感兴趣,这里有一个简单的解决方案:

        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()方法公开一个列表,你可以返回:toUnmodified(mNestedList),其中mNestedList是类中的私有列表。

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

    推荐文章