首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么使用不同的ArrayList构造函数会导致内部数组的增长率不同?

为什么使用不同的ArrayList构造函数会导致内部数组的增长率不同?
EN

Stack Overflow用户
提问于 2019-06-18 18:26:48
回答 6查看 1.1K关注 0票数 14

我似乎在ArrayList实现中偶然发现了一些我不能理解的有趣的东西。下面是一些代码,说明了我的意思:

代码语言:javascript
复制
public class Sandbox {

    private static final VarHandle VAR_HANDLE_ARRAY_LIST;

    static {
        try {
            Lookup lookupArrayList = MethodHandles.privateLookupIn(ArrayList.class, MethodHandles.lookup());
            VAR_HANDLE_ARRAY_LIST = lookupArrayList.findVarHandle(ArrayList.class, "elementData", Object[].class);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    public static void main(String[] args) {

        List<String> defaultConstructorList = new ArrayList<>();
        defaultConstructorList.add("one");

        Object[] elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(defaultConstructorList);
        System.out.println(elementData.length);

        List<String> zeroConstructorList = new ArrayList<>(0);
        zeroConstructorList.add("one");

        elementData = (Object[]) VAR_HANDLE_ARRAY_LIST.get(zeroConstructorList);
        System.out.println(elementData.length);

    }
}

我们的想法是,如果你创建一个这样的ArrayList

代码语言:javascript
复制
List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");

看看里面的elementData (保存所有元素的Object[])会报告什么10。因此,您添加了一个元素-您将获得9个未使用的额外插槽。

另一方面,如果你这样做:

代码语言:javascript
复制
List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");

您添加了一个元素,保留的空间仅用于该元素,没有其他内容。

在内部,这是通过两个字段实现的:

代码语言:javascript
复制
/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

通过new ArrayList(0)创建ArrayList时,将使用- EMPTY_ELEMENTDATA

通过new Arraylist()创建ArrayList时,将使用- DEFAULTCAPACITY_EMPTY_ELEMENTDATA

来自我内心的直观部分-简单地尖叫“删除DEFAULTCAPACITY_EMPTY_ELEMENTDATA”,让所有的情况都由EMPTY_ELEMENTDATA处理;当然是代码注释:

我们将其与EMPTY_ELEMENTDATA区分开来,以便了解在添加第一个元素时要膨胀多少

确实有道理,但为什么一个会膨胀到10 (比我要求的要多得多),而另一个会膨胀到1 (和我要求的一样多)。

即使你使用List<String> zeroConstructorList = new ArrayList<>(0),并不断添加元素,最终你也会发现elementData比请求的要大:

代码语言:javascript
复制
    List<String> zeroConstructorList = new ArrayList<>(0);
    zeroConstructorList.add("one");
    zeroConstructorList.add("two");
    zeroConstructorList.add("three");
    zeroConstructorList.add("four");
    zeroConstructorList.add("five"); // elementData will report 6, though there are 5 elements only

但它的增长速度比默认构造函数的情况要小。

这让我想起了HashMap实现,其中存储桶的数量几乎总是比您所要求的要多;但这样做是因为需要“2的幂”存储桶,而不是这里的情况。

所以问题是--有没有人能给我解释一下这种区别?

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56647032

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档