我有一个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[]
?
答案 0 :(得分:68)
Java中没有List<int>
这样的东西 - 泛型不支持原语。
仅在单个元素上进行自动装箱,而不是对于基元的数组。
至于如何纠正它 - 有各种各样的库,有很多方法可以做这样的事情。没有办法围绕这个,我不认为有任何东西可以让它在JDK中更容易。有些人会在包装器类型的列表中包装一个原始数组(以便在访问时发生装箱),其他人将遍历原始数组以创建一个独立的副本,就像他们去的那样。确保您知道自己在使用哪个。
(编辑:我一直认为int[]
的起点是不可协商的。如果你可以从Integer[]
开始,那么你就可以了:)
仅举一个辅助库的示例,并稍微插入Guava,com.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[][]
(此处,T
为int[]
)并最终得到1个元素List<int[]>
,这不是您想要的。
你仍然有一些不错的选择:
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中,您可以使用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 Collections从int
值数组中直接创建集合。这样就无需将int
到Integer
装箱了。
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
以及Set
,Bag
,Stack
和Map
。
注意:我是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[] 作为一个整体是一个对象,因此可以作为单个元素添加。