Arrays.asList() 存在疑问?

16

人们说asList方法将数组转换为列表而且不进行复制,所以对'aList'的任何更改都会反映到'a'中。因此,在'aList'中添加新值是不合法的,因为数组具有固定大小。

但是,asList()方法返回ArrayList<T>。编译器如何区分第3行和第5行。第3行会抛出异常 (UnsupportedOperationException)。

        String[] a = {"a","b","c","d"};//1
        List<String> aList =  Arrays.asList(a);//2
        aList.add("e");//3
        List<String> b = new ArrayList<String>();//4
        b.add("a");//5

7
重要的是 Javadoc 说了什么,而不是 '人们说' 了什么。 - user207421
8个回答

34

你从 Arrays.asList 得到的 List 实现是对数组的特殊视图-你无法更改它的大小。

Arrays.asList() 的返回类型是 java.util.Arrays.ArrayList,经常与 java.util.ArrayList 混淆。Arrays.ArrayList 只是把数组展示成一个列表。


3
我认为这基本上是问题的关键。OP看到返回类型是ArrayList,并想知道它为什么与ArrayList的行为不同。非常合理的问题。 - Joeri Hendrickx
Andreas_D,Arrays.asList(...) 的返回类型是 java.util.List 而不是 java.util.Arrays.ArrayList - Adil Hussain

10

再次阅读,Arrays.asList的类型是:

public static <T> List<T> asList(T... a)

这里明确说明asList返回一个实现了接口java.util.List的对象,但它并没有说明会返回class java.util.ArrayList 的实例。

接下来,注意到对List.add的说明:

boolean add(E e)

     将指定元素添加到此列表的末尾 (可选操作)

严格来说,每次使用定义为List类型(而不是ArrayList)的变量时,需要小心地预期该方法可能抛出UnsupportedOperationException。如果您确定只会收到始终具有正确语义的.add()的List实现,则可以忽略检查,但当您的假设无效时,可能会存在漏洞。


6

Manoj,

Arrays.List的返回类型是List接口的一些未知内部实现,而不是java.util.ArrayList,因此您只能将其分配给List类型。

如果您将其分配给ArrayList,例如它会在编译时出现错误“类型不匹配:无法从List转换为ArrayList”

  ArrayList<String> aList =  Arrays.asList(a);// gives Compile time error

根据Javadoc,“Arrays.asList返回由指定数组支持的固定大小列表(对返回的列表所做的更改“写入”到数组中)。 "这意味着您只提供了数组的列表视图,我认为它是在运行时创建的,当然您无法更改数组的大小,因此也无法更改“Arrays.asList”的大小。

依我看,Arrays.asList的内部实现具有所有可以更改数组大小的已实现方法,例如-

void add(E e)
{
//some unknown code
throw(java.lang.UnsupportedOperationException);
}

每当您试图更改数组的大小时,它都会抛出UnsupportedOperationException异常。

但是,如果您想通过使用这样的语法向ArrayList添加一些新项,可以通过创建Arraylist的子类来实现(最好使用ArrayList的匿名子类)。您可以将Arrays.List的返回类型传递给ArrayList的构造函数(即public ArrayList(Collection c)),类似于以下内容 -

List<String> girlFriends = new java.util.ArrayList<String>(Arrays.asList("Rose", "Leena", "Kim", "Tina"));
girlFriends.add("Sarah");

现在你可以使用相同的语法将Sarah轻松添加到你的女友列表中。

PS - 请将此选项或其他选项作为您的答案,因为已经解释了一切。 你低下的接受率非常令人沮丧。


5

asList() 方法返回的不是 java.util.ArrayList,而是 java.util.Arrays$ArrayList。这个类甚至没有继承 java.util.ArrayList,因此它的行为可能(并且确实)完全不同。

add() 方法是从 java.util.AbstractList 继承而来,默认情况下只会抛出 UnsupportedOperationException 异常。


不,asList返回一个列表。你所描述的可能对于特定的Java实现是正确的,但这并不是你可以依赖的东西。 - jarnbjo
@jarnbjo - 这对于Sun Java和GNU Classpath以及可能的任何其他实现都是正确的,因为这是最简单的方法。由于问题是关于编译器如何判断的,我认为一个具体的例子会更容易理解。 - OrangeDog

3
这是一个异常而不是编译器错误。它会在程序运行时抛出,而不是在编译时。基本上,Arrays.asList将返回的实际类在add()方法中有throw UnsupporteOperationException。
更具体地说,Arrays.asList将返回一个内部类,该内部类定义在Arrays类中,它派生自AbstractList并且不实现add方法。 AbstractList中的add方法实际上会抛出异常。

3
你假设Arrays.asList()返回一个ArrayList,但事实并非如此。Arrays.asList()返回一个未指定的List实现。该实现只是在每个不支持的方法上抛出UnsupportedOperationException

1
关键在于 List 实现的返回。
List<String> aList =  Arrays.asList(a);

如果您查看Arrays中的源代码,您会发现它包含一个内部私有静态类ArrayList。这与java.util.ArrayList不同。

0
asList返回一个固定大小的列表,因此您无法向其添加新元素。因为它返回的列表实际上是从创建它的数组(在您的情况下为'a')中派生的“视图”,所以您不能添加元素是有道理的 - 就像您不能向数组添加元素一样。请参阅asList的文档。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接