【问题标题】:Is there a generic way to create an un-modifiable List/Set/Map from Collection/List/Set... ?有没有一种通用的方法可以从 Collection/List/Set... 创建一个不可修改的 List/Set/Map?
【发布时间】:2016-08-13 08:10:37
【问题描述】:

java util Collections 类offers 围绕任何现有列表创建“不可修改”装饰器。但我们都知道(或在某些时候很难学习);它实际上只是最初传递给该调用的列表周围的装饰器。装饰列表不能更改;但是如果修改了“原始”列表,它将在幕后发生变化。

现在假设我有一些类似的课程

class Whatever {
   private final List<IDontCare> someElements;
   public Whatever(List<IDontCare> incomingElements) {
      someElements = unmodifiableCopyOf(incomingElements);

那个简单的类想要使用传入数据的真正不可修改的副本。好主意 - 但似乎没有干净/通用的方法来实现该方法unmodifiableCopyOf()

可以想到:

  • 使用“clone()”创建一个副本...不幸的是,“可见”clone() 仅存在于具体实现中,例如 ArrayList;但如果我只知道“它是实现列表的东西”……好吧;我无法克隆(很好地解释了here
  • 只需创建一个“中间容器”;像 new ArrayList(incomingElements) 并具有“装饰”;但是如果incomingElements 是一个链表呢?
  • 使用其他一些库,例如提供"A high-performance, immutable, random-access List implementation" 的 Guava。但好吧,Guava 在我这里不是一个选择(我们几乎仅限于我们自己的库和一些 Apache 公共资源)。

Tl;dr:对于这个问题,真的没有“通用”解决方案(依靠“标准库”)给我一个真正不可修改的集合吗?基于其他一些集合?

【问题讨论】:

标签: java collections clone


【解决方案1】:

有没有一种通用的方法可以从 Collection/List/Set... 创建一个不可修改的 List/Set/Map?

是的!使用Collections.unmodifiable...s。

Set<String> stuff = Collections.<String>unmodifiableSet(oldSet);

装饰列表不能更改;但是如果修改了“原始”列表,它将在幕后发生变化。

如果您不希望这样,那么问题在于处理原始集合而不是构建新集合。您应该在构建时获取一份副本。

    Set<String> uset = Collections.<String>unmodifiableSet(new HashSet<>(oldSet));

【讨论】:

  • 对不起;但这在第一段中是正确的。如果您在示例中更改 oldSet,则内容会发生变化。就试一试吧。但是,谢谢......我以某种方式提升了我的自尊心,一个拥有我 10 倍声誉的人弄错了那部分;-)
  • @Jägermeister - 是的 - 试图添加更多内容来涵盖您问题的另一面。
【解决方案2】:

选项 #1

public Whatever(List srcList) {
    Constructor<? extends List> c = srcList.getClass().getConstructor(Collection.class);
    someElements = unmodifiableList(c.newInstance(srcList));

try-catch 被省略。这适用于来自java.util 的列表,但不能保证自定义列表。

选项 #2

public Whatever(ArrayList srcList) {        
    someElements = unmodifiableList(new ArrayList(srcList));

public Whatever(LinkedList srcList) {        
    someElements = unmodifiableList(new LinkedList(srcList));

public Whatever(List srcList) {        
    someElements = unmodifiableList(new ArrayList(srcList)); // ok, no info

不要被这个解决方案欺骗,如果传递给构造函数的列表引用是List类型,将使用第三个构造函数。

【讨论】:

  • 这是正确的;很公平;我确实想到了类似的事情;但发现它“不够通用”——因为它仅适用于某些情况;并增加了很多关于 try/catch 的复杂性。
【解决方案3】:

tl;博士

Java 10 完全添加了您想要的内容:copyOf 方法,您可以在其中传递一个列表、集合或映射,并取回一个新副本,而不是 Collections.unmodifiable… 生成的原始视图。

  • List.copyOf
  • Set.copyOf
  • Map.copyOf

List.copyOf

在 Java 10 及更高版本中,将可修改的 List 传递给 List.copyOf

List< Person > peopleUnmod = List.copyOf( people ) ;

生成的列表是真正的副本,与原件分开,而不是像 Collections.unmodifiableList 那样对原件进行查看。

引用List.copyOf Javadoc:

返回一个unmodifiable List,其中包含给定集合的元素,按其迭代顺序。给定的 Collection 不得为 null,并且不得包含任何 null 元素。如果给定的 Collection 随后被修改,则返回的 List 将不会反映此类修改。

Set.copyOf

同样,Set 接口提供了一个Set.copyOf 方法来生成一组单独的新对象,这些对象与原始对象中的相同。

Map.copyOf

继续这个主题,Map 接口提供了一个Map.copyOf 方法来生成一个单独的新映射,该映射与原始映射中的键和值相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-10
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 2021-06-16
    相关资源
    最近更新 更多