栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

HashMap重新哈希/调整大小容量

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HashMap重新哈希/调整大小容量

文档中的这一行,

如果初始容量大于最大条目数除以负载因子,则将不会进行任何哈希操作。

确实可以追溯到在JDK 8(JEP 180)中添加树形实现之前。您可以在JDK
1.6
HashMap文档中
看到此文本。实际上,本文是在引入Collections
framework(包括HashMap)时一直追溯到JDK 1.2。您可以在网上找到JDK
1.2文档的非官方版本,或者如果您想亲自查看的话,可以从档案中下载一个版本。

我相信在添加树形实现之前,该文档是正确的。但是,正如您所观察到的,在某些情况下它是不正确的。该策略不仅是如果条目数除以负载因子而超出容量(实际上是表长度),那么可能会发生大小调整。如您所述,如果单个存储桶中的条目数超过TREEIFY_THRESHOLD(当前为8),但表长度小于MIN_TREEIFY_CAPACITY(当前为64),则
也会 发生大小调整。

您可以在

treeifyBin()
HashMap
的方法中看到此决定。

    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)        resize();    else if ((e = tab[index = (n - 1) & hash]) != null) {

当单个存储桶中的条目超过TREEIFY_THRESHOLD时,到达代码中的这一点。如果表大小等于或大于MIN_TREEIFY_CAPACITY,则此bin被树化;否则,仅调整表的大小。

请注意,在较小的表大小下,这可能会使垃圾箱中的条目多于TREEIFY_THRESHOLD。这并不难证明。首先,一些反射式的HashMap转储代码:

// run with --add-opens java.base/java.util=ALL-UNNAMEDstatic Class<?> classNode;static Class<?> classTreeNode;static Field fieldNodeNext;static Field fieldHashMapTable;static void init() throws ReflectiveOperationException {    classNode = Class.forName("java.util.HashMap$Node");    classTreeNode = Class.forName("java.util.HashMap$TreeNode");    fieldNodeNext = classNode.getDeclaredField("next");    fieldNodeNext.setAccessible(true);    fieldHashMapTable = HashMap.class.getDeclaredField("table");    fieldHashMapTable.setAccessible(true);}static void dumpMap(HashMap<?, ?> map) throws ReflectiveOperationException {    Object[] table = (Object[])fieldHashMapTable.get(map);    System.out.printf("map size = %d, table length = %d%n", map.size(), table.length);    for (int i = 0; i < table.length; i++) {        Object node = table[i];        if (node == null) continue;        System.out.printf("table[%d] = %s", i, classTreeNode.isInstance(node) ? "TreeNode" : "BasicNode");        for (; node != null; node = fieldNodeNext.get(node)) System.out.print(" " + node);        System.out.println();    }}

现在,让我们添加一串都属于同一存储桶的字符串。选择这些字符串,使它们的哈希值(由HashMap计算)均为0 mod 64。

public static void main(String[] args) throws ReflectiveOperationException {    init();    List<String> list = List.of(        "LBCDD", "IKBNU", "WZQAG", "MKEAZ", "BBCHF", "KRQHE", "ZZMWH", "FHLVH",        "ZFLXM", "TXXPE", "NSJDQ", "BXDMJ", "OFBCR", "WVSIG", "HQDXY");    HashMap<String, String> map = new HashMap<>(1, 10.0f);    for (String s : list) {        System.out.println("===> put " + s);        map.put(s, s);        dumpMap(map);    }}

从初始表大小1和可笑的负载因子开始,这会将8个条目放入单独的存储桶中。然后,每次添加另一个条目时,将调整表的大小(加倍),但所有条目最终都位于同一存储桶中。这最终导致表的大小为64,其中一个存储桶具有长度为14的线性节点链(“基本节点”),然后添加下一个条目,最终将其转换为树。

该程序的输出如下:

===> put LBCDDmap size = 1, table length = 1table[0] = BasicNode LBCDD=LBCDD===> put IKBNUmap size = 2, table length = 1table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU===> put WZQAGmap size = 3, table length = 1table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG===> put MKEAZmap size = 4, table length = 1table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ===> put BBCHFmap size = 5, table length = 1table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF===> put KRQHEmap size = 6, table length = 1table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE===> put ZZMWHmap size = 7, table length = 1table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH===> put FHLVHmap size = 8, table length = 1table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH===> put ZFLXMmap size = 9, table length = 2table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH ZFLXM=ZFLXM===> put TXXPEmap size = 10, table length = 4table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH ZFLXM=ZFLXM TXXPE=TXXPE===> put NSJDQmap size = 11, table length = 8table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH ZFLXM=ZFLXM TXXPE=TXXPE NSJDQ=NSJDQ===> put BXDMJmap size = 12, table length = 16table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH ZFLXM=ZFLXM TXXPE=TXXPE NSJDQ=NSJDQ BXDMJ=BXDMJ===> put OFBCRmap size = 13, table length = 32table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH ZFLXM=ZFLXM TXXPE=TXXPE NSJDQ=NSJDQ BXDMJ=BXDMJ OFBCR=OFBCR===> put WVSIGmap size = 14, table length = 64table[0] = BasicNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH ZFLXM=ZFLXM TXXPE=TXXPE NSJDQ=NSJDQ BXDMJ=BXDMJ OFBCR=OFBCR WVSIG=WVSIG===> put HQDXYmap size = 15, table length = 64table[0] = TreeNode LBCDD=LBCDD IKBNU=IKBNU WZQAG=WZQAG MKEAZ=MKEAZ BBCHF=BBCHF KRQHE=KRQHE ZZMWH=ZZMWH FHLVH=FHLVH ZFLXM=ZFLXM TXXPE=TXXPE NSJDQ=NSJDQ BXDMJ=BXDMJ OFBCR=OFBCR WVSIG=WVSIG HQDXY=HQDXY


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/463367.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号