是否有可能找出某个列表是否是固定大小的?



是否有可能找出某个列表是否是固定大小的? 我的意思是,例如这段代码:

String[] arr = {"a", "b"};
List<String> list = Arrays.asList(array);

返回由数组支持的固定大小List。但是,是否可以在不尝试添加/删除元素并捕获异常的情况下以编程方式了解List是否为固定大小?例如:

try {
list.add("c");
}
catch(UnsupportedOperationException e) {
// Fixed-size?
}

String[]创建的列表

List<String> list = Arrays.asList(array);

Arrays作为封闭类,而由例如创建的new ArrayList()将没有封闭类。因此,以下内容应该可以检查列表是否由于调用Arrays.toList()而生成:

static <T> boolean wasListProducedAsAResultOfCallingTheFunctionArrays_asList(List<T> l) {
return Arrays.class.equals(l.getClass().getEnclosingClass());
}

请注意,此方法依赖于未记录的行为。如果他们将另一个嵌套的 List 子类添加到 Arrays 类,它将中断。

是否有可能找出某个列表是否是固定大小的?

理论上 - 没有。 固定大小是列表类实现的紧急属性。 只能通过尝试添加元素来确定列表是否具有该属性。

请注意,简单的行为测试无法可靠地区分固定大小的列表和有界列表或永久或临时只读的列表。


实际上,固定大小的列表通常具有与普通列表不同的类。 您可以测试对象的类,以查看它是否是特定类。 因此,如果您了解哪些类用于在代码库中实现固定大小的列表,那么您可以测试特定列表是否为固定大小。

例如,Arrays.asList(...)方法返回一个List对象,其实际类为java.util.Arrays.ArrayList。 这是一个私有嵌套类,但您可以使用反射找到它,然后使用Object.getClass().equals(...)来测试它。

然而,这种方法是脆弱的。 如果修改了Arrays的实现,或者您也开始使用其他形式的固定大小列表,则代码可能会中断。

No.

无论列表是否可扩展,列表 API 都是相同的,这是故意的。

列表 API 中也没有任何内容允许您查询它以确定此功能。

您无法通过反射完全可靠地确定此信息,因为您将依赖于实现的内部详细信息,并且因为存在无限数量的类,这些类可能是固定大小的。例如,除了Arrays.asList,还有Arrays.asList().subList,它恰好返回一个不同的类。基本列表周围也可以有包装器,如Collections.checkedListCollections.synchronizedListCollections.unmodifiableList。还有其他固定大小的列表:Collections.emptyListCollections.singletonListCollections.nCopies。在标准图书馆之外,还有类似 番石榴的ImmutableList.通过扩展AbstractList手动滚动列表也是非常简单的(对于固定大小的列表,您只需要实现size()get(int)方法(。

即使您检测到列表不是固定大小的,List.add的规范也允许它出于其他原因拒绝元素。例如,Collections.checkedList包装器会为不需要类型的元素抛出ClassCastException

即使您知道您的列表是可扩展的,并且允许任意元素,这并不意味着您想使用它。也许它是同步的,或者没有同步的,或者不可序列化的,或者它是一个慢速链表,或者具有一些你不想要的其他质量。

如果要控制列表的类型、可变性、可序列化性或线程安全性,或者希望确保没有其他代码保留对它的引用,则做法是自己创建一个新代码。当不必要的情况下这样做并不昂贵(memcopy 非常快(,它可以让您更明确地推理您的代码在运行时实际会做。如果您确实想避免创建不必要的副本,请尝试将列表类列入白名单,而不是将列表类列入黑名单。例如:

if (list.getClass() != ArrayList.class) {
list = new ArrayList<>(list);
}

(注意:这使用getClass而不是instanceof,因为instanceof对于ArrayList的任何奇怪的子类也是如此。

java-9 中存在不可变的集合,但仍然没有通用的@Immutable注释,或者我们可以查询以获取此信息的公共标记接口。

我能想到的最简单的方法是简单地获取此类实例的类的名称:

String nameList = List.of(1, 2, 3).getClass().getName();
System.out.println(nameList.contains("Immutable"));

但这仍然依赖于内部细节,因为它查询 公共类ImmutableCollections的名称 ,这不是公开的,显然可以在不另行通知的情况下进行更改。

最新更新