是否有可能找出一些列表是否固定大小? 我的意思是,例如这段代码:
String[] arr = {"a", "b"};
List<String> list = Arrays.asList(array);
返回由数组支持的固定大小List
。但是,如果List
是固定大小而不尝试添加/删除元素并捕获异常,是否有可能以编程方式理解?例如:
try {
list.add("c");
}
catch(UnsupportedOperationException e) {
// Fixed-size?
}
答案 0 :(得分:14)
从String[]
按
List<String> list = Arrays.asList(array);
将Arrays
作为封闭类,而由new ArrayList()
创建的一个将不具有封闭类。因此,以下内容应该可以检查List是否是由于调用Arrays.toList()
生成的:
static <T> boolean wasListProducedAsAResultOfCallingTheFunctionArrays_asList(List<T> l) {
return Arrays.class.equals(l.getClass().getEnclosingClass());
}
请注意,此方法依赖于未记录的行为。如果他们将另一个嵌套的List子类添加到Arrays类,它将会中断。
答案 1 :(得分:6)
是否可以查明某些列表是否为固定大小?
理论上 - 否。固定大小是列表类实现的新兴属性。您只能通过尝试添加元素来确定列表是否具有该属性。
请注意,简单的行为测试无法可靠地区分固定大小的列表和有界列表,或者永久或暂时只读的列表。
实际上,固定大小的列表通常与普通的列表具有不同的类别。您可以测试对象的类,以查看它是否是特定的类。因此,如果您了解将用于在代码库中实现固定大小的列表 ,那么您可以测试特定列表是否是固定大小的。
例如,Arrays.asList(...)
方法返回实际类为List
的{{1}}对象。这是一个私有嵌套类,但您可以使用反射查找它,然后使用java.util.Arrays.ArrayList
来测试它。
然而,这种方法很脆弱。如果Object.getClass().equals(...)
的实现被修改,或者您开始使用其他形式的固定大小列表,您的代码可能会中断。
答案 2 :(得分:2)
没有
无论List是否可扩展,List API都是相同的,deliberate。
List API中也没有任何内容允许您查询它以确定此功能。
您无法通过反射完全可靠地确定此信息,因为您将依赖于实现的内部详细信息,并且因为存在可能固定大小的无限数量的类。例如,除Arrays.asList
之外,还有Arrays.asList().subList
,它恰好返回不同的类。基本列表周围也可能有包装,如Collections.checkedList
,Collections.synchronizedList
和Collections.unmodifiableList
。还有其他固定大小的列表:Collections.emptyList
,Collections.singletonList
和Collections.nCopies
。在标准库之外,还有Guava的ImmutableList
之类的东西。通过扩展AbstractList
手动滚动列表也是非常简单的(对于固定大小的列表,您只需要实现size()
和get(int)
方法)。
即使您检测到列表不是固定大小,List.add
的规范也允许它出于其他原因拒绝元素。例如,Collections.checkedList
包装器会为不需要的类型的元素抛出ClassCastException
。
即使你知道你的列表是可扩展的,并允许任意元素,这并不意味着你想要使用它。也许它是同步的,或者不是同步的,或者是不可序列化的,或者它是一个慢速的链表,或者是你不想要的其他质量。
如果你想控制列表的类型,可变性,可串行性或线程安全性,或者你想确保没有其他代码保留对它的引用,那么你可以自己创建一个新的代码。在不必要的情况下(memcopies速度极快)这样做并不昂贵,并且它可以让你更明确地了解你的代码在运行时实际会做什么。如果您真的想避免创建不必要的副本,请尝试白名单,而不是将列表类列入黑名单。例如:
if (list.getClass() != ArrayList.class) {
list = new ArrayList<>(list);
}
(注意:这使用getClass
代替instanceof
,因为instanceof
对于ArrayList
的任何奇怪子类也都适用。)
答案 3 :(得分:0)
java-9中有不可变的集合,但是仍然没有常见的@Immutable
注释或者我们可以查询以获取此信息的公共标记接口。
我能想到的最简单的方法就是获取这样一个实例的类的名称:
String nameList = List.of(1, 2, 3).getClass().getName();
System.out.println(nameList.contains("Immutable"));
但仍然依赖于内部细节,因为它查询公共类ImmutableCollections
的名称,这不是公开的,显然可以更改,恕不另行通知。