对于 Android 编程,如果我在一个方法中创建一个 ArrayList 并且知道当我从该方法返回它时列表会有多大,我应该在创建它时指定列表的初始大小吗?
我问是因为通常我们不会费心指定初始大小,但也许它在为移动设备编程时会有所不同。
谢谢。
编辑
我说的是我确实知道列表的最终大小的情况(例如,我正在从 A 类型的对象列表中创建 B 类型的对象列表)。
编辑 2
是否有任何与此相关的性能指标?
是的,如果您知道列表将有多大,那么您绝对应该指定初始大小。它将提高性能。
如果您使用默认构造函数,则初始大小将为 0。来自Android 文档:
public ArrayList()
构造一个初始容量为零ArrayList
的新实例。
和代码:
public ArrayList() {
array = EmptyArray.OBJECT;
}
因此,稍后当您添加元素时,内部Object[] array
将调整大小:
@Override public boolean add(E object) {
Object[] a = array;
int s = size;
if (s == a.length) {
Object[] newArray = new Object[s +
(s < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : s >> 1)];
System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
a[s] = object;
size = s + 1;
modCount++;
return true;
}
这是Android的代码ArrayList
。
因此,为了不浪费时间调整大小,最好指定ArrayList
.
ArrayList
旨在根据其内容自动调整自身。您可以预先分配内存,但最终会根据您使用ArrayList
. 这无关紧要,除非您正在构建一个巨大的列表,该列表将持续一段时间,因为 Java 使用垃圾收集进行堆清理。
如果您知道 List 或任何集合的大小,那么提前指定大小的性能要高得多。原因是因为它需要周期来增长一个集合,这取决于实现可能更多也可能更少。
我认为这里与任何其他 java 应用程序一样。只有当它被证明是一个瓶颈时,你才应该关心这些微优化。JCF 中的数据结构具有合理的默认值:
ArrayList() {
this(10);
}
这是ArrayList
.
您应该注意的是方法的空间和时间复杂度。
是的,ArrayList 旨在处理动态大小,但如果您之前知道列表将包含多少项目,那么以指定的大小开始是一个好习惯,其他开发人员更容易阅读代码。
因此,根据我的经验,除非您在部署后预计会出现扩展问题(不确定您想要使用 List 的确切用途,所以为了安全起见),没有理由指定大小。我的意思是,如果你肯定知道它永远是 10,那么,无论如何。那会很棒。
现在您可以做的是将插入命令放入一个廉价(性能)的 IF 语句中以进行一些内存管理。找出您要定位的任何设备,并为您的应用程序占用合理的内存空间。如果插入语句会超出此范围,则提示用户选择继续并冒性能问题的风险,完全拒绝插入,或者可能开始删除旧内容。
同样,不知道您的确切情况有点难以建议,但总的来说,如果您可以绝对说列表将在 10 时达到最大值,那么一定要初始化为 10。但如果您这样做,您不会受到太大伤害让它打勾。
是的,ArrayList
在这种情况下,您应该将容量传递给构造函数,原因如下:
您将调用的构造函数如下:
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
通过传递 ,initialCapacity
您可以设置支持ArrayList
.
假设您要添加到列表中,并且该元素会导致列表调整大小。这是将发生的一系列函数调用:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
总之,如果您知道最终大小,通过将其传递给构造函数,您将保证永远不需要重新调整数组的大小。
如果最终容量足够大并且在ArrayList
很长一段时间内将相对无人居住,那么您可能不想分配那么多内存,即在必要时让它自行调整大小可能会更好。否则,我会通过初始容量。