我似乎在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");
看看里面的elementData
(保存所有元素的Object[]
)会报告什么10
。因此,您添加了一个元素-您将获得9个未使用的额外插槽。
另一方面,如果你这样做:
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 = {};
通过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
比请求的要大:
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的幂”存储桶,而不是这里的情况。
所以问题是--有没有人能给我解释一下这种区别?
https://stackoverflow.com/questions/56647032
复制相似问题