为什么使用不同的 ArrayList 构造函数会导致内部数组的增长率不同?
我似乎在实现中偶然发现了一些有趣的事情,我无法理解。下面是一些代码,显示了我的意思:ArrayList
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
List<String> defaultConstructorList = new ArrayList<>();
defaultConstructorList.add("one");
看看里面的东西(保存所有元素的地方)它将报告。因此,您添加一个元素 - 您将获得9个未使用的额外插槽。elementData
Object[]
10
另一方面,如果您这样做:
List<String> zeroConstructorList = new ArrayList<>(0);
zeroConstructorList.add("one");
你添加一个元素,保留的空间只为该元素,仅此而已。
在内部,这是通过两个字段实现的:
/**
* 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 = {};
当您创建 via 时,将使用 - 。ArrayList
new ArrayList(0)
EMPTY_ELEMENTDATA
创建 via 时, 将使用 - 。ArrayList
new Arraylist()
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
来自我内心的直观部分 - 简单地尖叫“删除”,让所有案件都得到处理;当然是代码注释:DEFAULTCAPACITY_EMPTY_ELEMENTDATA
EMPTY_ELEMENTDATA
我们将其与EMPTY_ELEMENTDATA区分开来,以了解添加第一个元素时要膨胀多少
确实有意义,但是为什么一个会膨胀到(比我要求的多得多),而另一个会膨胀(完全符合我的要求)。10
1
即使您使用 ,并继续添加元素,最终您也会达到比请求的点更大的点:List<String> zeroConstructorList = new ArrayList<>(0)
elementData
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
所以问题是 - 有人可以向我解释这种差异吗?