在上周的文章中,我们讲了字符串拼接的多种方式,在StringBuilder和StrngBuffer的抽象父类AbstractStringBuilder的append方法中,我们使用了ensureCapacityInternal函数,今天我就带大家看看了解下这个函数
//调用函数,这里的调用顺序就是自上而下的
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
//从0开始复制数组本身,并采用新的长度
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
//返回新的容量
private int newCapacity(int minCapacity) {
// overflow-conscious code
//在这里,正数的左移1位指2进制的数左移一位,再用0补充;如原来是0011(3),左移为0110(6)
//他们的十进制之间的关系是2倍的关系,即2的一次方
int newCapacity = (value.length << 1) + 2;
//当新的容量仍然小于实际需要的长度的时候
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
//举例,当value.length为2136372536的时候,newCapacity的符号位由于溢出而改变,
//超过int的最大值,因此符号位变成了"1",也就是由正数变成负数,这时便满足<=0条件
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
//用于巨大的新容量的获取
//个人理解:数据和对象的长度并不是真正的由MAX_ARRAY_SIZE来决定,而是由你实际上存储的jvm虚拟机的存储来决定的
//情况1:举个例子,你的int数组的长度是21亿,他需要21亿乘4字节,估算就是8.4G,这通常会超过我们设置的jvm的堆空间大小
//这就是为什么我们超堆内存创建数组的时候,他会报出OutOfMemoryError: Java heap space
//情况2:而当我们超jvm规范创建数据的时候,如Integer.MAX_VALUE-1和Integer.MAX_VALUE;他会报出OutOfMemoryError: Requested array size exceeds VM limit;或许不同的jvm有不同的底线吧
//情况3:而当我们超过Integer.MAX_VALUE,他传递给StringBuilder的值超过了int类型的最大值,底层会变成了负数,他会报出NegativeArraySizeException
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
//返回最小容量和最大的数组容量中更大的那个
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
总结
1. 个人疑惑:在学习源码的过程中,我在思考为什么MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8,查询说是要存储一些关键的信息?为什么arraylist中的hugeCapacity是可以超过MAX_ARRAY_SIZE的值的,凭什么,你能超出,我却不能?
2. 闲聊:写代码的过程中查询了很多资料,有时候在想为什么要写博客,明明很多人都已经写过了,你再写又有什么意义呢。往大一点说,我想看看别人帅气的代码,了解哪些伟大的程序员所做过的事;往小了说,我以前就希望当我有一天离开这个世界的时候,有本书它记录着我从小到大的生活经历和感悟,写博客也是一种记录吧,也许有一天当我看见这些博客,也会回忆起那些晚上打字的时光,或许那也是一种年轻的回忆呢,哈哈哈!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。