初始容量问题

ArrayList 的构造问题:
这里写图片描述

1 构造指定容量的对象
2 构造empty对象
3 从一个Collection构造对象

看前两个,默认构造和带容量构造。看过源码后可以发现。
不指定容量的话,默认构造一个length是10的Object数组(JDK8是一个空数组)。
然后每add一次,判断是不是需要扩容了。是的话,扩1/2。

为方便计算我们假设可以声明的数组的最大长度是21亿整,大于21亿就认为溢出。
每扩大1/2达到一个大1/2的数字。
如,放11个元素,此时容量会是15。下一次是15 + (15 >> 1) ,依次是22,33,
49,73………..直到大于21亿时溢出。

会出现的问题:
1、
很极端的情况下一个ArrayList可能无法使用的空间最多是7亿 -1。因为容量在14亿 + 1时再扩容会溢出。这时候是明明有空间供扩容,但是表示ArrayList容量的int值已经溢出了。

2、
由于数组声明后长度不可变。所以每次库容都是new一个是原来3/2的数组,
然后旧的拷贝到新的。每次扩容都浪费3/2的空间。

3、
自动管理的容量很有可能不会完全用完,比如有5个元素,容量会是10;
有12个元素,容量会是15;有16个时,是22。已占用的空间浪费率最大是
(新容量 - (旧容量 + 1)) / 新容量。如:add 11个元素时:
(15 - (10 + 1D) )/ 15 = 0.26666666。旧容量越大,这个值越接近于1/3,浪费率越大。

只要是以数组形式实现的,都应该提供自定义容量的方法,否则是不合常理的。
还有常用的StringBuilder、HashMap等最好尽量指定初始容量。
StringBuilder时 * 2 + 1;HashMap是大于等于指定的容量的最小的2的n次方数,
为的是寻找分组时,使用 &运算——i % 2^n 与 i & (2^n -1)相等。
HashMap扩容时更大的一个2^n,StingBuilder是当前容量 * 2再加2,空间占用都
远大于ArrayList。

比如遍历一个用户列表,把手机号拼接为一个【手机号,手机号,手机号】的字符串,
这时候由于list.size()和手机号长度已知,可以直接给StringBuilder指定初始容量。

并且很多情况下放入HashMap的K都是已知的,比如用于方法返回值的Map:
此时的K数量是已知的,所以初始容量可以指定2,并且此时的”msg”
和”isok”很可能不会有hash冲突,所以装载率参数也最好不用默认的0.75F而是1。

这里写图片描述

即使两个K会产生hash冲突也无所谓,一是仅2条数据不至于对效率产生影响,二
是此处用Map明显是想返回多个值,而不是用的hash查找特性。

内部数组实现的都要尽量指定初始容量。
好多人用ArrayList不管放几个还是几百上千个东西,都是用默认无参构造。
用HashMap不管是两个还是几十个也是用无参构造。
具体加不加初始容量的内存占用区别,可以用freeMemory()看一下。
类似代码都是不会出现问题,但是一旦出问题就是OutOfMemory,然后一群人在那喊“优化”,想想就好笑,连个数组形式容器加容量参数都不知道的人,也可以喊“优化”。我是不明白他们理解的优化到底是做什么。还有就是,你既然有能力去优化,为什么不一开始就做好,而是出了问题后来弥补。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值