Arrays.asList()不能正常工作?

时间:2009-09-23 18:48:21

标签: java arrays list variadic-functions

我有一个float [],我希望获得一个包含相同元素的列表。我可以做一个又一个添加它们的丑陋的事情,但我想使用Arrays.asList方法。但是有一个问题。这有效:

List<Integer> list = Arrays.asList(1,2,3,4,5);

但事实并非如此。

int[] ints = new int[] {1,2,3,4,5};
List<Integer> list = Arrays.asList(ints);

asList方法接受一个varargs参数,据我所知,这是一个数组的“简写”。

问题:

  • 为什么第二段代码会返回List<int[]>而不是List<int>

  • 有没有办法纠正它?

  • 为什么自动装箱不在这里工作;即int[]Integer[]

11 个答案:

答案 0 :(得分:68)

Java中没有List<int>这样的东西 - 泛型不支持原语。

仅在单个元素上进行自动装箱,而不是对于基元的数组

至于如何纠正它 - 有各种各样的库,有很多方法可以做这样的事情。没有办法围绕这个,我不认为有任何东西可以让它在JDK中更容易。有些人会在包装器类型的列表中包装一个原始数组(以便在访问时发生装箱),其他人将遍历原始数组以创建一个独立的副本,就像他们去的那样。确保您知道自己在使用哪个。

(编辑:我一直认为int[]的起点是不可协商的。如果你可以从Integer[]开始,那么你就可以了:)

仅举一个辅助库的示例,并稍微插入Guavacom.google.common.primitive.Ints.asList

答案 1 :(得分:23)

这个怎么样?

Integer[] ints = new Integer[] {1,2,3,4,5};
List<Integer> list = Arrays.asList(ints);

答案 2 :(得分:13)

因为java数组是对象而Arrays.asList()将你的int数组视为varargs列表中的单个参数。

答案 3 :(得分:11)

输入Java 8,您可以执行以下操作来收集盒装数组:

Integer[] boxedInts = IntStream.of(ints).boxed().toArray(Integer[]::new);

或者这是收集在盒装列表中

List<Integer> boxedInts = IntStream.of(ints).boxed().collect(Collectors.toList());

但是,这仅适用于int[]long[]double[]。这不适用于byte[]

请注意,Arrays.stream(ints)IntStream.of(ints)是等效的。所以前两个例子也可以改写为:

Integer[] boxedIntArray = Arrays.stream(ints).boxed().toArray(Integer[]::new);
List<Integer> boxedIntList = Arrays.stream(ints).boxed().collect(Collectors.toList());

最后一种形式可能会受到青睐,因为它省略了Stream的原始特定子类型。但是,在内部它仍然是一堆重载的,在这种情况下仍然在内部创建IntStream

答案 4 :(得分:4)

问题不在于Arrays.asList()。问题是你希望自动装箱能够在阵列上工作 - 而事实并非如此。在第一种情况下,编译器会在查看它们用于的内容之前自动执行各个int。在第二种情况下,首先将它们放入一个int数组(不需要自动装箱),然后将其传递给Arrays.asList()(不能自动进行自动装箱)。

答案 5 :(得分:2)

Arrays.asList(T... a)有效地使用T[]作为数组匹配任何真实对象数组(Object的子类)。唯一不匹配的是基元数组,因为基本类型不是从Object派生的。因此int[]不是Object[]

然后发生的是,varags机制启动并将其视为传递单个对象,并创建该类型的单个元素数组。因此,您传递int[][](此处,Tint[])并最终得到1个元素List<int[]>,这不是您想要的。

你仍然有一些不错的选择:

Guava的Int.asList(int[])适配器

如果您的项目已经使用了番石榴,那就像使用Guava提供的适配器一样简单:Int.asList()。相关类中的每种基本类型都有一个类似的适配器,例如,Booleans用于boolean等。

int foo[] = {1,2,3,4,5};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
    System.out.println(i);
}

这种方法的优点是它在现有数组周围创建了一个瘦包装器,因此包装器的创建是恒定时间(不依赖于数组的大小),并且所需的存储空间很小除了基础整数数组之外的常量(小于100个字节)。

缺点是访问每个元素需要底层int的装箱操作,并且设置需要拆箱。如果您大量访问列表,这可能会导致大量的瞬态内存分配。如果平均多次访问每个对象,最好使用一次将对象装箱并将其存储为Integer的实现。下面的解决方案就是这样做的。

Java 8 IntStream

在Java 8中,您可以使用Arrays.stream(int[])方法将int数组转换为Stream。根据您的使用情况,您可以直接使用流,例如,使用forEach(IntConsumer)对每个元素执行某些操作。在这种情况下,这个解决方案非常快,根本不会产生任何装箱或拆箱,并且不会创建底层阵列的任何副本。

或者,如果您确实需要List<Integer>,则可以将stream.boxed().collect(Collectors.toList())用作suggested here。这种方法的缺点是它完全封装了列表中的每个元素,这可能会使其内存占用量增加近一个数量级,它会创建一个新的Object[]来保存所有盒装元素。如果您随后大量使用该列表并且需要Integer个对象而不是int s,这可能会有所回报,但这是值得注意的。

答案 6 :(得分:2)

  

为什么这里不进行自动装箱;即int []到Integer []?

虽然自动装箱会将int转换为Integer,但不会将int[]转换为Integer[]

为什么不呢?

简单(但不令人满意)的答案是因为这就是JLS所说的。 (如果愿意,可以检查一下。)

真正的答案对于自动装箱以及安全性至关重要。

1自动装箱到代码中的任何位置时,都会得到相同的Integer对象。对于所有int值而言,情况并非如此(由于Integer自动装箱缓存的大小有限),但是如果您使用equals比较Integer对象,则会得到“正确答案。

基本上N == N始终为true,new Integer(N).equals(new Integer(N))始终为true。此外,假设您坚持使用纯Java代码,这两个东西仍然为true。

现在考虑一下:

int[] x = new int[]{1};
int[] y = new int[]{1};

这些相等吗?没有! x == y为假,x.equals(y)为假!但为什么?因为:

y[0] = 2;

换句话说,具有相同类型,大小和内容的两个数组始终是可区分的,因为Java数组是可变的。

自动装箱的“承诺”是可以这样做的,因为结果是无法区分的 1 。但是,由于对数组和数组可变性的equals的定义,所有数组在根本上都是可区分的。因此,如果允许对原始类型数组进行自动装箱,则会破坏“承诺”。


1-.....,前提是您不使用==测试自动装箱的值是否相等。

答案 7 :(得分:1)

如果您将int[]传递给Arrays.asList(),则创建的列表将为List<int[]>,这在java中不是vaild,而不是正确的List<Integer>

我认为您希望Arrays.asList()能够自动设置您的整数,正如您所见,它不会。

答案 8 :(得分:1)

无法将int[]转换为Integer[],您必须复制值


int[] tab = new int[]{1, 2, 3, 4, 5};
List<Integer> list = ArraysHelper.asList(tab);

public static List<Integer> asList(int[] a) {
    List<Integer> list = new ArrayList<Integer>();
    for (int i = 0; i < a.length && list.add(a[i]); i++);
    return list;
}

答案 9 :(得分:0)

或者,您可以使用IntList作为类型,并使用factory中的IntLists Eclipse Collectionsint值数组中直接创建集合。这样就无需将intInteger装箱了。

IntList intList1 = IntLists.mutable.with(1,2,3,4,5);
int[] ints = new int[] {1,2,3,4,5};
IntList intList2 = IntLists.mutable.with(ints);
Assert.assertEquals(intList1, intList2);

Eclipse Collections支持可变和不可变的原语List以及SetBagStackMap

注意:我是Eclipse Collections的提交者。

答案 10 :(得分:0)

public class Utils { private Utils() { } public static JwtAuthenticationToken getMockJwtToken(String role, String subject){ final var roles = new JSONArray(); roles.add(role); final Map<String, JSONArray> jsonMap = new HashMap<>(); jsonMap.put("roles", roles); final var claimObject = new JSONObject(jsonMap); final var jwt = Jwt.withTokenValue("token") .header("alg", "none") .claim("realm_access", claimObject) .subject(subject) .build(); final Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_my_role)); return new JwtAuthenticationToken(jwt, authorities); } } 是原始类型。 Arrays.asList() 接受泛型类型 T,它仅适用于引用类型(对象类型),而不适用于基元。由于 int[] 作为一个整体是一个对象,因此可以作为单个元素添加。