将一个ArrayList转换为不可修改的ArrayList

4

我正在尝试将一个不可修改的ArrayList赋值给一个final变量EX_FIELDS。exList是一个现有的ArrayList对象。

EX_FIELDS = (ArrayList<String>) Collections.unmodifiableList(exList);

这段代码存在于静态块中。当类加载时,我会收到以下错误。

java.lang.ClassCastException: java.util.Collections$UnmodifiableRandomAccessList cannot be cast to java.util.ArrayList

我需要使用EX_FIELDS来支持随机访问。是否有其他方法可以实现它?非常感谢您的帮助。

4个回答

14

EX_FIELDS 应该是 List<String> 类型,而不是 ArrayList<String>,您不需要进行任何转换:您只需编写以下内容:

EX_FIELDS = Collections.unmodifiableList(exList);

这是一个更为一般性的规则的一个实例,即你应该按照接口而不是实现去编程。


或者,如果相关的话,可以使用RandomAccessList - 静态方法确实保留了区别。 - chrylis -cautiouslyoptimistic-
我正在尝试使用列表进行常规随机访问,因此认为这将是高效的。 - amudhan3093
使用List接口。相信实现。这是最佳实践。 - Louis Wasserman

3
你会收到一个ClassCastException异常,因为 Collections.unmodifiableList() 不会返回一个ArrayList,而是返回一个实现List接口的任何后备类的 List<T>(接口)。从异常中可以看出,它实际上返回了一个 UnmodifiableRandomAccessList

当你创建变量 EX_FIELDS 时,应该这样声明:

List<String> EX_FIELDS = new ArrayList<>();

也就是说,EX_FIELDS是一个列表(List),而你选择了一个实际实例为ArrayList。稍后你将会完成该操作。
EX_FIELDS = Collections.unmodifiableList(exList);

unmodifiableList() 返回一个List,但实际上你并不关心它是哪种类型,只要它符合List接口就可以了。


0
其他答案都是正确的,但缺少一个关键点:以这种方式创建的不可修改列表仍然可以被修改。
调用Collections类会创建一个包装器对象,该对象包装所提供的exList参数。
换句话说:当exList发生改变时,您的包装列表也会发生改变。
因此,当您想要确保时,您必须先创建一个新的临时列表,将exList的所有条目添加到其中;然后使用该Collections方法将其包装在临时副本周围。

所以我应该将它作为EX_FIELDS = Collections.unmodifiableList(new ArrayList<String>(exList))传递,这样现在引用被维护了吗? - amudhan3093
我认为是这样(但我不能百分之百确定那个ArrayList构造函数是否真的会创建一个副本...所以,如果你想要确定,最好查看源代码)。顺便说一句,这是个好问题。 - GhostCat

0
错误发生的原因是Collections.unmodifiablelist(exList)返回了一个列表,而你试图做的是

ArrayList<T> EX_FIELDS=(ArrayList<T>)List<T>();

List是一个接口,不能被实例化。EX_FIELDS变量只能存储ArrayList对象,因此会出现类转换异常错误。

正确的做法是:

List<String> EX_FIELDS=Collections.unmodifiablelist(exList)

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