题 从数组创建ArrayList


我有一个初始化的数组,如:

Element[] array = {new Element(1), new Element(2), new Element(3)};

我想将此数组转换为ArrayList类的对象。

ArrayList<Element> arraylist = ???;

2967
2017-10-01 14:38


起源


在Java9中 - > List <String> list = List.of(“Hello”,“World”,“from”,“Java”); - MarekM
@MarekM这个答案是错误的,因为这不会返回 ArrayList。海报专门询问了这一点。 - Tobias Weimer
我认为他没有使用List接口,因为这是最好的做法。但是如果你想要的话是 - 新的ArrayList <>(List.of(“Hello”,“World”,“from”,“Java”)); - MarekM
重点不在于使用界面,关键是在您的解决方案中,返回的列表是不可修改的。这可能是一个更大的问题,也是他要求一个ArrayList的原因 - Tobias Weimer


答案:


new ArrayList<>(Arrays.asList(array))

3971
2017-10-01 14:39



是的。在(最常见的)你只想要一个列表的情况下, new ArrayList 电话也是不必要的。 - Calum
@Luron - 只是用 List<ClassName> list = Arrays.asList(array) - Pool
@Calum和@Pool - 正如Alex Miller的回答中所述,使用 Arrays.asList(array) 没有把它传递给新的 ArrayList 对象将修复列表的大小。使用的一个更常见的原因 ArrayList 是能够动态地改变它的大小,你的建议会阻止这个。 - Code Jockey
Arrays.asList()是一个可怕的函数,你永远不应该只使用它的返回值。它打破了List模板,所以总是以这里指出的形式使用它,即使它看起来多余。好答案。 - Adam
@Adam请研究java.util.List的javadoc。 add的合约允许他们抛出UnsupportedOperationException。 docs.oracle.com/javase/7/docs/api/java/util/...  不可否认,从面向对象的角度来看,为了使用集合,您必须多次了解具体实现并不是很好 - 这是一个实用的设计选择,以保持框架简单。 - lbalazscs


鉴于:

Element[] array = new Element[] { new Element(1), new Element(2), new Element(3) };

最简单的答案是:

List<Element> list = Arrays.asList(array);

这样可以正常工作。但有些警告:

  1. 从asList返回的列表 固定大小。因此,如果您希望能够在代码中添加或删除返回列表中的元素,则需要将其包装在新代码中 ArrayList。否则你会得到一个 UnsupportedOperationException
  2. 从中返回的列表 asList() 由原始数组支持。如果修改原始数组,则也会修改列表。这可能是令人惊讶的。

775
2017-10-01 15:39



两种操作的时间复杂度是多少?我的意思是使用和不使用明确的arraylist结构。 - damned
Arrays.asList()只是通过包装现有数组来创建一个ArrayList,因此它是O(1)。 - Alex Miller
包装新的ArrayList()将导致固定大小列表的所有元素被迭代并添加到新的ArrayList中,因此是O(n)。 - Alex Miller
asList()返回的List的实现没有实现List的几个方法(如add(),remove(),clear()等等),这解释了UnsupportedOperationException。绝对是一个警告...... - sethro
当问题要求“ArrayList类的一个对象”时,我认为假设它引用的类是合理的 java.util.ArrayList。 Arrays.asList实际上返回一个 java.util.Arrays.ArrayList 这不是 instanceof 另一堂课。因此,第三个警告是,如果您尝试在需要上述内容的上下文中使用它,它将无法工作。 - Dave L.


(旧线程,但只有2美分,因为没有提到番石榴或其他图书馆和其他一些细节)

如果可以,请使用番石榴

值得指出的是Guava方式,它极大地简化了这些恶作剧:

用法

对于不可变列表

使用 ImmutableList 阶级及其 of() 和 copyOf() 工厂方法 (元素不能为null)

List<String> il = ImmutableList.of("string", "elements");  // from varargs
List<String> il = ImmutableList.copyOf(aStringArray);      // from array

对于可变列表

使用 Lists 阶级及其 newArrayList() 工厂方法:

List<String> l1 = Lists.newArrayList(anotherListOrCollection);    // from collection
List<String> l2 = Lists.newArrayList(aStringArray);               // from array
List<String> l3 = Lists.newArrayList("or", "string", "elements"); // from varargs

还请注意其他类中其他数据结构的类似方法,例如 Sets

为何选择番石榴?

使用番石榴时,主要的吸引力可能是减少因类型安全的仿制品而造成的混乱 工厂方法 允许在大多数时间推断类型。然而,自Java 7与新的钻石操作员一起到达以来,这个论点持有的水量更少。

但这不是唯一的原因(并且Java 7还没有到处):简写语法也非常方便,如上所述,方法初始化器允许编写更具表现力的代码。你在一个Guava调用中执行当前Java集合需要2。


如果你不能......

对于不可变列表

使用JDK Arrays 阶级及其 asList() 工厂方法,包裹着 Collections.unmodifiableList()

List<String> l1 = Collections.unmodifiableList(Arrays.asList(anArrayOfElements));
List<String> l2 = Collections.unmodifiableList(Arrays.asList("element1", "element2"));

请注意返回的类型 asList() 是一个 List 使用混凝土 ArrayList 实施,但 不是这样  java.util.ArrayList。它是一种内部类型,它模仿一个 ArrayList 但实际上直接引用传递的数组并使其“直写”(修改反映在数组中)。

它禁止通过一些修改 List API的方法只需简单地扩展一个 AbstractList (因此,不支持添加或删除元素),但它允许调用 set() 覆盖元素。因此,这个列表并不是真正的不可变和调用 asList() 应该包裹着 Collections.unmodifiableList()

如果需要可变列表,请参阅下一步。

对于可变列表

与上面相同,但用实际包装 java.util.ArrayList

List<String> l1  = new ArrayList<String>(Arrays.asList(array));    // Java 1.5 to 1.6
List<String> l1b = new ArrayList<>(Arrays.asList(array));          // Java 1.7+
List<String> l2  = new ArrayList<String>(Arrays.asList("a", "b")); // Java 1.5 to 1.6
List<String> l2b = new ArrayList<>(Arrays.asList("a", "b"));       // Java 1.7+

教育目的:良好的手工方式

// for Java 1.5+
static <T> List<T> arrayToList(final T[] array) {
  final List<T> l = new ArrayList<T>(array.length);

  for (final T s : array) {
    l.add(s);
  }
  return (l);
}

// for Java < 1.5 (no generics, no compile-time type-safety, boo!)
static List arrayToList(final Object[] array) {
  final List l = new ArrayList(array.length);

  for (int i = 0; i < array.length; i++) {
    l.add(array[i]);
  }
  return (l);
}

295
2017-11-16 17:16



+1但请注意 List 归来的 Arrays.asList 是可变的,你仍然可以 set 元素 - 它只是不可调整大小。对于没有Guava的不可变列表,您可能会提到 Collections.unmodifiableList。 - Paul Bellora
@haylem在你的部分 教育目的:良好的手工方式, 你的 arrayToList for Java 1.5+不正确。你正在实施清单 String,并尝试从给定的数组中检索字符串,而不是使用泛型参数类型, T。除此之外,良好的答案,以及+1作为唯一一个包括手动方式。 - afsantos


由于这个问题已经很老了,令我惊讶的是没有人提出最简单的形式:

List<Element> arraylist = Arrays.asList(new Element(1), new Element(2), new Element(3));

从Java 5开始, Arrays.asList() 采用varargs参数,您不必显式构造数组。


203
2018-06-22 11:30



尤其是, List<String> a = Arrays.asList("first","second","third") - 18446744073709551615


new ArrayList<T>(Arrays.asList(myArray));

确保这一点 myArray 与...类型相同 T。如果您尝试创建一个,则会出现编译器错误 List<Integer>从一个数组 int, 例如。


172
2017-10-01 14:40





另一种方式(虽然基本上相当于 new ArrayList(Arrays.asList(array)) 解决方案性能方面:

Collections.addAll(arraylist, array);

77
2018-04-03 23:20





您可能只需要一个List,而不是ArrayList。在这种情况下,您可以这样做:

List<Element> arraylist = Arrays.asList(array);

62
2017-10-01 14:45



这将由原始输入数组支持,这就是您(可能)想要将其包装在新的ArrayList中的原因。 - Bill the Lizard
小心这个解决方案。如果你看,Arrays不会返回一个真正的java.util.ArrayList。它返回一个实现所需方法的内部类,但您无法更改列表中的成员。它只是一个数组的包装器。 - Mikezx6r
您可以将List <Element>项强制转换为ArrayList <Element> - monksy
@ Mikezx6r:小 更正:这是一个固定大小的列表。您可以更改列表的元素(set 方法),你不能改变列表的大小(不是 add 要么 remove 元素)! - Carlos Heuberger
是的,但需要注意的是,这取决于您要对列表执行的操作。值得注意的是,如果OP只想迭代元素,则根本不需要转换数组。 - PaulMurrayCbr


Java 9

Java 9, 您可以使用 List.of 静态工厂方法,以创建一个 List 文字。类似于以下内容:

List<Element> elements = List.of(new Element(1), new Element(2), new Element(3));

这将返回一个 一成不变 列表包含三个元素。如果你想要一个 易变的 列表,将该列表传递给 ArrayList 构造函数:

new ArrayList<>(List.of(// elements vararg))

JEP 269:收集的便利工厂方法

JEP 269 提供一些方便的工厂方法 Java集合 API。这些不可变的静态工厂方法内置于 ListSet,和 Map Java 9及更高版本中的接口。


59
2018-04-17 16:58





另一个更新,即将结束的2014年,您也可以使用Java 8:

ArrayList<Element> arrayList = Stream.of(myArray).collect(Collectors.toCollection(ArrayList::new));

如果这可能只是一个字符,则会保存一些字符 List 

List<Element> list = Stream.of(myArray).collect(Collectors.toList());

54
2017-11-25 20:48



最好不要依赖于实现,但是 Collectors.toList() 实际上返回一个 ArrayList。 - bcsb1001
不正确使用Stream.of(...);这将创建一个元素流。请改用Arrays.stream - Patrick Parker
我不这么认为,2个选项是有效的,但是Arrays.stream稍微“更好”,因为你可以用固定大小创建它,使用带有'start','end'args的重载方法。也可以看看: stackoverflow.com/a/27888447/2619091 - whyem


要将数组转换为ArrayList,开发人员通常会这样做:

List<String> list = Arrays.asList(arr);// this is wrong way..

Arrays.asList() 将返回一个ArrayList,它是一个 private static class inside Arrays,它不是java.util.ArrayList类。 The java.util.Arrays.ArrayList 上课了 set(), get(), contains() 方法,但没有任何添加元素的方法,所以它的大小是固定的。 要创建一个真正的ArrayList,您必须:

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

ArrayList的构造函数可以接受 收集类型,这也是一种超级类型 java.util.Arrays.ArrayList


47
2018-06-25 07:20



如果你只是需要一个,这不是错误的方式 List,而且不需要 ArrayList,你实际上并不是大部分时间。大多数时候开发人员创建一个 ArrayList 这是出于习惯,不仅仅是出于需要。 - Christoffer Hammarström
同意@ChristofferHammarström,两者都有效 List<String> list = Arrays.asList(arr);用来创造 List 和 ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));用来创造 ArrayList。可能@Nepster只是复制粘贴了一个摘录 programcreek.com/2013/04/... - Nikhil Katre