将ArrayList转换为Collections.synchronizedList

时间:2017-11-30 21:01:34

标签: java list arraylist collections

我知道ArrayList不是线程安全的,我见过很多人推荐 在(Collections.synchronizedList)转换它。我需要创建一个系统,将ArrayList转换为(Collections.synchronizedList),然后再转回ArrayList。但首先我需要在a中插入b

问题是我不知道如何从(Collections.synchronizedList)转换为ArrayList,当我尝试插入以下元素时出现错误:

public List<Object> a;
public List<ArrayList<Object>> b;

a = Collections.synchronizedList(new ArrayList<Object>());
b = Collections.synchronizedList(b);

当我尝试以下命令时会抛出异常:

b.add(id, (ArrayList<Object>) a);
  

java.base / java.util.Collections $ SynchronizedRandomAccessList无法强制转换为java.base / java.util.ArrayList

4 个答案:

答案 0 :(得分:1)

有一个ArrayList构造函数需要Collection

ArrayList<Object> arrayList = new ArrayList<>(a);

但是,将b的类型更改为List<List<Object>>可能更合理:

public List<ArrayList<Object>> b;
b.add(id, a);

答案 1 :(得分:1)

您最好将b变量更改为:

public List<List<Object>> b;

并不依赖于具体的实现。它可以传递您想要的任何List实现 - ArrayListCollections.SynchronizedList

否则,如果您不想更改字段类型(我不建议这样做),您可以使用复制构造函数:

b.add(2, new ArrayList<>(a));

或Stream API方法:

b.add(2, a.stream().collect(Collectors.toCollection(ArrayList::new)));

答案 2 :(得分:0)

说明

这很简单。您的b变量的类型为:

List<ArrayList<Object>> b

因此它包含ArrayList<Object>类型而非List<Object>类型的元素。因此,当您尝试插入a时,编译器会抱怨,因为a不是ArrayList<Object>类型(但它从来没有)。您已使用

创建了它
a = Collections.synchronizedList(...);

方法Collections#synchronizedList 返回ArrayList,它返回List

解决方案

将您的b对象更改为

List<List<Object>> b

您将可以插入a

或者,您需要再次明确地将a转换为ArrayList。例如,使用。

ArrayList<Object> resultA = new ArrayList<>(a);

然后插入resultA。给定的构造函数创建一个新的ArrayList,它添加给定集合的所有元素。

答案 3 :(得分:0)

a)小心,Collections.synchronizedList()不会使您的列表完全是线程安全的,它只是同步您的操作。如果您有多个线程读取和写入列表,如果您不知道自己在做什么,可能仍会遇到ConcurrentModificationException。如果您想要更好的线程安全性,请使用CopyOnWriteArrayList。例如,如果一个线程将项添加到List,而另一个线程迭代,则会破坏除CopyOnWriteArrayList之外的任何List实现,无论它是否包含在Collections.synchronizedList()中。

b)Collections.synchronizedList()是原始列表周围的decorator。即你的ArrayList仍然存在于装饰器内部。您不需要将其复制回来,只需保留对原始ArrayList变量的引用。您对同步列表所做的每个更改都会传播到ArrayList。另一方面:为什么需要ArrayList?一个好的api将接受任何List类型。依赖ArrayList作为实现类型违反了至少一个Effective Java规则(第52项:通过其接口引用对象)。因此,除非您针对显式需要ArrayList的API进行编码,否则只需使用同步列表(将字段类型更改为List<List<Object>>)。