关于不可变列表(由 Arrays.asList() 创建)

Posted

技术标签:

【中文标题】关于不可变列表(由 Arrays.asList() 创建)【英文标题】:Regarding immutable List (created by Arrays.asList()) 【发布时间】:2014-10-16 08:04:28 【问题描述】:

当我们使用java.util.Arrays.asList() 从数组创建列表时,列表是不可变的。我只是想知道当List(或SetMap)的基本目的是具有动态大小并能够随意添加、删除元素时,我们为什么要创建一个不可变列表。当我们需要固定大小的数据结构时,我们选择 Array,当我们需要动态数据结构时,我们选择 ListSetMap 等。那么拥有不可变列表的目的是什么?我在执行任务时遇到了这个问题。

【问题讨论】:

可变的意思是不可变的? “在这种情况下”是什么意思?一般来说,我觉得你的问题很难理解。您似乎混淆了数组和列表的概念。 抱歉我的问题有错误。现在更正它们。请检查。 【参考方案1】:

当我们使用 java.util.Arrays.asList() 从数组创建列表时,列表是可变的。

是和否:可以通过调用修改列表

list.set(index, element);

但列表可能不会在结构上进行修改。这意味着不可能向列表中添加元素或从列表中删除元素。原因很简单,列表仍然是由数组支持的,数组的大小可能不会改变。

当我们需要一个固定大小的可变集合时,我们会选择 Array

这就是这里的关键点:数组不是Collection。 Arrays.asList 方法主要充当“数组世界”和“集合世界”之间的“桥梁”。

Arrays.asList 方法允许您将数据传递给需要 Collection 的方法:

// A method that expects a collection:
void process(List<String> strings)  ... 

void call()

    String array[] = new String[]  "A", "B", "C" ;

    // Pass the array (as a list) to the method:
    process(Arrays.asList(array));

此应用案例包括从数组创建其他集合。例如,如果您有一个数组并想创建一个包含数组元素的Set,您可以

String array[] = new String[]  "A", "B", "C" ;
Set<String> set = new HashSet<String>();
for (String s : array) 

    set.add(s);

但是使用Arrays.asList 方法可以更方便地做到这一点:

Set<String> set = new HashSet<String>(Arrays.asList(array));

Arrays.asList 方法可以说是 Collection#toArray 方法的对应物,它的工作方向相反(尽管这种方法通常涉及创建和填充一个 new 数组,而 @ 987654333@ 方法只是“包装”一个数组并让它“看起来像”List)。

【讨论】:

我同意 asList 方法充当 Arrays 世界和 Collections 世界之间的桥梁。我也同意有一些方法可以从 Array 创建一个可变列表。但我不清楚为什么一个列表会出现asList 是不可变的吗?使其不可变的主要目的是什么? @Venkat 我已经说过可以修改它的元素,但不能修改列表的大小。其原因是实现了List 接口,以便实际的data 仍然存储在数组中。而在Java中,数组的大小是不能改变的。如果要从数组创建可变列表,可以使用new ArrayList&lt;String&gt;(Arrays.asList(array));。所以他们没有“故意”使列表在结构上不可变。这只是列表由数组支持这一事实的副作用。 public E set(int index, E element) throw new UnsupportedOperationException(); 【参考方案2】:

是因为AbstractList类中的add(),由Arrays java类(内部使用)下自定义的ArrayList(内部静态类)扩展而来。请注意,这个 add() 方法与 java.util.ArrayList 中定义的不同,而是 java.util.Arrays$ArrayList 中定义的。

数组具有固定大小的属性,由 jvm 本地提供。即使 Arrays.copyOf() 用于增加大小,例如 Arrays.copyOf(arr, 10); //10 is the length,其中原始数组是 arr= int[]1,2 // size is two。它使用System.arraycopy() 创建总是一个新数组,最终调用本机方法

[static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)]

请注意,上面的列表只有大小限制,如果你真的想让可变列表不可变,请尝试使用Collections.unmodifiableList(mutableList); 不变性不是 jvm 定义的概念,而是开发人员的想法。请参考https://***.com/a/42071121/5620851和https://***.com/a/42138471/5620851

【讨论】:

【参考方案3】:

java.util.Arrays.asList() 调用 return new ArrayList&lt;&gt;(a); 但是这个 ArrayList 是一个私有的数组类,它扩展了AbstractList 并覆盖了一些实现。因此,期望java.util.ArrayList 的行为是不公平的。如果您查看java.util.AbstractList,您会发现您可以调用 add(E e) 但不能调用很多其他方法。因此,按照当前的实现,您可以在列表底部添加一个元素,但不能更改列表的现有结构。

【讨论】:

一直认为返回的ArrayListjava.util.ArrayList。从来不知道这是一个完全不同的课程。【参考方案4】:

如果您拨打System.out.println(Arrays.asList("a", "b").getClass());

运行时类型为java.util.Arrays$ArrayList

但是如果你打电话给System.out.println(new ArrayList&lt;&gt;(Arrays.asList("a", "b").getClass()));

运行时类型是java.util.ArrayList

也许这种区别会有所帮助。

【讨论】:

以上是关于关于不可变列表(由 Arrays.asList() 创建)的主要内容,如果未能解决你的问题,请参考以下文章

可变参数的使用

Arrays.asList()vs Collections.singletonList()

使用 Arrays.asList 抛出 java.lang.UnsupportedOperationException

使用 Arrays.asList 抛出 java.lang.UnsupportedOperationException

JDK5的新特性之可变参数&Arrays.asList()方法

JAVA不可变List的实现