您现在的位置是:亿华云 > 系统运维
HashMap中傻傻分不清楚的那些概念
亿华云2025-10-08 23:26:03【系统运维】8人已围观
简介很多人在通过阅读源码的方式学习Java,这是个很好的方式。而JDK的源码自然是***。在JDK的众多类中,我觉得HashMap及其相关的类是设计的比较好的。很多人读过HashMap的代码,不知道你们有
很多人在通过阅读源码的傻傻方式学习Java,这是清楚个很好的方式。而JDK的概念源码自然是***。在JDK的傻傻众多类中,我觉得HashMap及其相关的清楚类是设计的比较好的。很多人读过HashMap的概念代码,不知道你们有没有和我一样,傻傻觉得HashMap中关于容量相关的清楚参数定义的太多了,傻傻分不清楚。概念
其实,傻傻这篇文章介绍的清楚内容比较简单,只要认真的概念看看HashMap的原理还是可以理解的,单独写一篇文章的傻傻原因是因为我后面还有几篇关于HashMap源码分析的文章,源码库这些概念不熟悉的清楚话阅读后面的文章会很吃力。
HashMap中重要的概念成员变量
先来看一下,HashMap中都定义了哪些成员变量。
上面是一张HashMap中主要的成员变量的图,其中有一个是我们本文主要关注的: size、loadFactor、threshold、DEFAULT_LOAD_FACTOR和DEFAULT_INITIAL_CAPACITY。
我们先来简单解释一下这些参数的含义,然后再分析他们的作用。
HashMap类中有以下主要成员变量:
transient int size;记录了Map中KV对的个数
loadFactor装载印子,用来衡量HashMap满的程度。loadFactor的默认值为0.75f(static final float DEFAULT_LOAD_FACTOR = 0.75f;)。
int threshold;临界值,当实际KV个数超过threshold时,HashMap会将容量扩容,threshold=容量*加载因子
除了以上这些重要成员变量外,HashMap中还有一个和他们紧密相关的概念:capacity容量,如果不指定,云服务器默认容量是16(static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;)
可能看完了你还是有点蒙,size和capacity之间有啥关系?为啥要定义这两个变量。loadFactor和threshold又是干啥的?
size 和 capacity
HashMap中的size和capacity之间的区别其实解释起来也挺简单的。我们知道,HashMap就像一个“桶”,那么capacity就是这个桶“当前”最多可以装多少元素,而size表示这个桶已经装了多少元素。来看下以下代码:
Map<String, String> map = new HashMap<String, String>(); map.put("hollis", "hollischuang"); Class<?> mapType = map.getClass(); Method capacity = mapType.getDeclaredMethod("capacity"); capacity.setAccessible(true); System.out.println("capacity : " + capacity.invoke(map)); Field size = mapType.getDeclaredField("size"); size.setAccessible(true); System.out.println("size : " + size.get(map));我们定义了一个新的HashMap,并想其中put了一个元素,然后通过反射的方式打印capacity和size。输出结果为:capacity : 16、size : 1
默认情况下,一个HashMap的容量(capacity)是16,设计成16的好处我在《全网把Map中的hash()分析的最透彻的文章,别无二家。》中也简单介绍过,主要是站群服务器可以使用按位与替代取模来提升hash的效率。
为什么我刚刚说capacity就是这个桶“当前”最多可以装多少元素呢?当前怎么理解呢。其实,HashMap是具有扩容机制的。在一个HashMap***次初始化的时候,默认情况下他的容量是16,当达到扩容条件的时候,就需要进行扩容了,会从16扩容成32。
我们知道,HashMap的重载的构造函数中,有一个是支持传入initialCapacity的,那么我们尝试着设置一下,看结果如何。
Map<String, String> map = new HashMap<String, String>(1); map.put("hahaha", "hollischuang"); Class<?> mapType = map.getClass(); Method capacity = mapType.getDeclaredMethod("capacity"); capacity.setAccessible(true); System.out.println("capacity : " + capacity.invoke(map)); Map<String, String> map = new HashMap<String, String>(7); map.put("hahaha", "hollischuang"); Class<?> mapType = map.getClass(); Method capacity = mapType.getDeclaredMethod("capacity"); capacity.setAccessible(true); System.out.println("capacity : " + capacity.invoke(map)); Map<String, String> map = new HashMap<String, String>(9); map.put("hahaha", "hollischuang"); Class<?> mapType = map.getClass(); Method capacity = mapType.getDeclaredMethod("capacity"); capacity.setAccessible(true); System.out.println("capacity : " + capacity.invoke(map));分别执行以上3段代码,分别输出:capacity : 2、capacity : 8、capacity : 16。
也就是说,默认情况下HashMap的容量是16,但是,如果用户通过构造函数指定了一个数字作为容量,那么Hash会选择大于该数字的***个2的幂作为容量。(1->2、7->8、9->16)
这里有一个小建议:在初始化HashMap的时候,应该尽量指定其大小。尤其是当你已知map中存放的元素个数时。(《阿里巴巴Java开发规约》)
loadFactor 和 threshold
前面我们提到过,HashMap有扩容机制,就是当达到扩容条件时会进行扩容,从16扩容到32、64、128...
那么,这个扩容条件指的是什么呢?
其实,HashMap的扩容条件就是当HashMap中的元素个数(size)超过临界值(threshold)时就会自动扩容。
在HashMap中,threshold = loadFactor * capacity。
loadFactor是装载因子,表示HashMap满的程度,默认值为0.75f,设置成0.75有一个好处,那就是0.75正好是3/4,而capacity又是2的幂。所以,两个数的乘积都是整数(capacity为2也同样)。
对于一个默认的HashMap来说,默认情况下,当其size大于12(16*0.75)时就会触发扩容。
验证代码如下:
Map<String, String> map = new HashMap<>(); map.put("hollis1", "hollischuang"); map.put("hollis2", "hollischuang"); map.put("hollis3", "hollischuang"); map.put("hollis4", "hollischuang"); map.put("hollis5", "hollischuang"); map.put("hollis6", "hollischuang"); map.put("hollis7", "hollischuang"); map.put("hollis8", "hollischuang"); map.put("hollis9", "hollischuang"); map.put("hollis10", "hollischuang"); map.put("hollis11", "hollischuang"); map.put("hollis12", "hollischuang"); Class<?> mapType = map.getClass(); Method capacity = mapType.getDeclaredMethod("capacity"); capacity.setAccessible(true); System.out.println("capacity : " + capacity.invoke(map)); Field size = mapType.getDeclaredField("size"); size.setAccessible(true); System.out.println("size : " + size.get(map)); Field threshold = mapType.getDeclaredField("threshold"); threshold.setAccessible(true); System.out.println("threshold : " + threshold.get(map)); Field loadFactor = mapType.getDeclaredField("loadFactor"); loadFactor.setAccessible(true); System.out.println("loadFactor : " + loadFactor.get(map)); map.put("hollis13", "hollischuang"); Method capacity = mapType.getDeclaredMethod("capacity"); capacity.setAccessible(true); System.out.println("capacity : " + capacity.invoke(map)); Field size = mapType.getDeclaredField("size"); size.setAccessible(true); System.out.println("size : " + size.get(map)); Field threshold = mapType.getDeclaredField("threshold"); threshold.setAccessible(true); System.out.println("threshold : " + threshold.get(map)); Field loadFactor = mapType.getDeclaredField("loadFactor"); loadFactor.setAccessible(true); System.out.println("loadFactor : " + loadFactor.get(map));输出结果:
capacity : 16 size : 12 threshold : 12 loadFactor : 0.75 capacity : 32 size : 13 threshold : 24 loadFactor : 0.75当HashMap中的元素个数达到13的时候,capacity就从16扩容到32了。
HashMap中还提供了一个支持传入initialCapacity,loadFactor两个参数的方法,来初始化容量和装载因子。不过,一般不建议修改loadFactor的值。
总结
HashMap中size表示当前共有多少个KV对,capacity表示当前HashMap的容量是多少,默认值是16,每次扩容都是成倍的。loadFactor是装载因子,当Map中元素个数超过loadFactor* capacity的值时,会触发扩容。loadFactor* capacity可以用threshold表示。
【本文是专栏作者Hollis的原创文章,作者微信公众号Hollis(ID:hollischuang)】
戳这里,看该作者更多好文
很赞哦!(65347)
相关文章
- 为什么现在中文域名觉得好?使用中文域名有什么好处?
- 四、配置网站,填充内容
- cm域名有什么独特之处?新人要了解cm域名哪些?
- 打开https://www.aizhan.com/输入自己想要查询的域名然后按回车键,如果做过网站都会有数据显示出来
- 4、注册门槛低
- 用户邮箱的静态密码可能已被钓鱼和同一密码泄露。在没有收到安全警报的情况下,用户在适当的时间内不能更改密码。在此期间,攻击者可以随意输入帐户。启用辅助身份验证后,如果攻击者无法获取移动电话动态密码,他将无法进行身份验证。这样,除非用户的电子邮件密码和手机同时被盗,否则攻击者很难破解用户的邮箱。
- 4、参加域名拍卖会
- 第五步:重复第四步,直到找到正确的纪录。
- 公司和个人选域名方法一样吗?有什么不同?
- 只要我们做的是从目前的市场情况选择域名,从简单易记,从个性特征上,我们就可以找到一个好域名进行注册。域名注册进行域名记录和解析以及绑定网站后,客户可以通过URL登录您的网站。
热门文章
站长推荐
审核通过的域名将显示在域名竞拍页面,并进入正式拍卖期,买家可以在拍卖周期内出价,加价幅度与拍卖保证金说明,点此查看。
5. 四种状态过后,域名管理机构释放域名给公众注册。
ICANN 规章禁止转移已经被记录或者在60天前内转移的域名。
5. 四种状态过后,域名管理机构释放域名给公众注册。
这个不用多说,不同平台的注册价格不同,且不同平台对域名释放交易的把控与曝光不同,当然价格相对便宜且平台渠道广操作便利的平台最好。
众所周知,com域名拥有最大的流通市场和流通历史。最好选择com域名,特别是在购买域名时处理域名。其次可以是cn域名、net域名、org域名等主流域名,现在比较流行的王域名和顶级域名,都是值得注册和投资的。
4、待所有域名查询结束后可在右侧点击导出结果,即可以excel的文件方式将查询到的结果导出。
3、商标域名一经注册,就可以作为域名裁决过程中的主要信息之一。这可以大大增加公司被抢注的相关域名胜诉的机会。