3

对于 Android 编程,如果我在一个方法中创建一个 ArrayList 并且知道当我从该方法返回它时列表会有多大,我应该在创建它时指定列表的初始大小吗?

我问是因为通常我们不会费心指定初始大小,但也许它在为移动设备编程时会有所不同。

谢谢。

编辑

我说的是我确实知道列表的最终大小的情况(例如,我正在从 A 类型的对象列表中创建 B 类型的对象列表)。

编辑 2

是否有任何与此相关的性能指标?

4

7 回答 7

1

是的,如果您知道列表将有多大,那么您绝对应该指定初始大小。它将提高性能。

如果您使用默认构造函数,则初始大小将为 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.

于 2013-11-14T19:40:39.257 回答
0

ArrayList旨在根据其内容自动调整自身。您可以预先分配内存,但最终会根据您使用ArrayList. 这无关紧要,除非您正在构建一个巨大的列表,该列表将持续一段时间,因为 Java 使用垃圾收集进行堆清理。

于 2013-11-12T19:16:30.307 回答
0

如果您知道 List 或任何集合的大小,那么提前指定大小的性能要高得多。原因是因为它需要周期来增长一个集合,这取决于实现可能更多也可能更少。

于 2013-11-12T19:17:48.043 回答
0

我认为这里与任何其他 java 应用程序一样。只有当它被证明是一个瓶颈时,你才应该关心这些微优化。JCF 中的数据结构具有合理的默认值:

ArrayList() {
     this(10);
}

这是ArrayList.

您应该注意的是方法的空间时间复杂度。

于 2013-11-12T19:19:03.773 回答
0

是的,ArrayList 旨在处理动态大小,但如果您之前知道列表将包含多少项目,那么以指定的大小开始是一个好习惯,其他开发人员更容易阅读代码。

于 2013-11-12T19:20:16.780 回答
0

因此,根据我的经验,除非您在部署后预计会出现扩展问题(不确定您想要使用 List 的确切用途,所以为了安全起见),没有理由指定大小。我的意思是,如果你肯定知道它永远是 10,那么,无论如何。那会很棒。

现在您可以做的是将插入命令放入一个廉价(性能)的 IF 语句中以进行一些内存管理。找出您要定位的任何设备,并为您的应用程序占用合理的内存空间。如果插入语句会超出此范围,则提示用户选择继续并冒性能问题的风险,完全拒绝插入,或者可能开始删除旧内容。

同样,不知道您的确切情况有点难以建议,但总的来说,如果您可以绝对说列表将在 10 时达到最大值,那么一定要初始化为 10。但如果您这样做,您不会受到太大伤害让它打勾。

于 2013-11-16T05:11:47.090 回答
0

是的,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很长一段时间内将相对无人居住,那么您可能不想分配那么多内存,即在必要时让它自行调整大小可能会更好。否则,我会通过初始容量。

于 2013-11-18T04:44:38.557 回答