- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章关于Java HashMap自动排序的简单剖析由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1.HashMap概述 。
HashMap是无序的,这里无序的意思是你取出数据的顺序与你存入数据的顺序不同 。
2.发现问题 。
当尝试向HashMap中存入int类型的key,可以看到在输出的时候会自动排序 。
HashMap<Integer, String> map = new HashMap<>(); map.put(3, "asdf"); map.put(2, "asdf"); map.put(1, "asdf"); map.put(6, "asdf"); map.put(5, "asdf"); map.put(4, "asdf"); map.put(8, "asdf"); map.put(9, "asdf"); map.put(7, "asdf"); map.put(0, "asdf");
输出 。
3.实现原理 。
我们都知道,HashMap是数组加链表实现的,在链表长度大于8的时候将链表转化为红黑树 数组加链表画一下模型图是这样的,黑色的是数组,橙色的是链表,遍历HashMap的key的时候,先遍历第一列,然后第二列。。.
4.翻看源码 。
HashMap的默认数组长度为16,默认负载因子是0.75,意思就是当数组内不为null的元素大于(数组长度*负载因子)的时候就会拓容数组 。
如果数组长度和负载因子都是默认值,那当在数组中存入第13个元素后就会拓容16*0.75=12 。
/** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 /** * The load factor used when none specified in constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f;
再读一下put方法和hash方法 。
public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } //获取key的hash,当key为int类型的时候hash=key的值 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; //tab就是HashMap的数组,这句话就是初始化数组 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //如果根据hash值来判断将此元素放在什么位置,如果数组当前位置 //为空直接存放,成为一个长度为一的链表 if ((p = tab[i = (n - 1) & hash]) == null)//================== tab[i] = newNode(hash, key, value, null); //如果不是,则将当前元素放在当前位置下元素的后边形成链表 else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) //拓容数组 resize(); afterNodeInsertion(evict); return null; }
5.分析 。
17行:if ((p = tab[i = (n - 1) & hash]) == null) 。
(n - 1) & hash 。
n-1就是数组的length-1,现在数组长度是16, 。
15&hash, 。
例如,现在存入key为1, 。
15转成二进制为1111 。
1 转成二进制为0001.
所以i=15&1=1; 。
现在1就存放在数组下标为1的位置 。
如果放2,那就放在数组下标为2的位置, 。
如果再存放17的话, 。
1501111 。
1710001 。
15&17=1;因为数组下标1的位置有上一次存放的key为1的元素,所以就将key=17的元素挂在key=1的下边, 。
这是遍历HashMap的key就会变成1,17,2 。
顺序就会乱掉,现在数组的长度是16,已使用的是2,还没有达到拓容那一步, 。
6.验证 。
下边的代码是存放11个数据,拓容要存入第13个数据时进行拓容 。
HashMap<Integer, String> map = new HashMap<>(); map.put(3, "asdf"); map.put(2, "asdf"); map.put(1, "asdf"); map.put(6, "asdf"); map.put(5, "asdf"); map.put(4, "asdf"); map.put(8, "asdf"); map.put(9, "asdf"); map.put(7, "asdf"); map.put(0, "asdf"); map.put(17,"saf");// map.put(10,"saf");// map.put(11,"saf"); for (int i : map.keySet()) { System.out.println("key=" + i); } System.out.println("map.size()===============" + map.size());
下边这段代码的输出结果就是 。
和分析的一样, 。
如果再添加两个数据,使其拓容 。
HashMap<Integer, String> map = new HashMap<>(); map.put(3, "asdf"); map.put(2, "asdf"); map.put(1, "asdf"); map.put(6, "asdf"); map.put(5, "asdf"); map.put(4, "asdf"); map.put(8, "asdf"); map.put(9, "asdf"); map.put(7, "asdf"); map.put(0, "asdf"); map.put(17,"saf");// map.put(10,"saf");// map.put(11,"saf"); for (int i : map.keySet()) { System.out.println("key=" + i); } System.out.println("map.size()===============" + map.size());
输出是 。
又排好了顺序 。
7.结论 。
当所有key的hash的最大值<数组的长度-1时HashMap可以将存入的元素按照key的hash从小到大排序 不过这个发现没有什么用就是了,不过看了一天源码收获不少,还看到好几种没见过的写法 。
到此这篇关于关于Java HashMap自动排序简单剖析的文章就介绍到这了,更多相关Java HashMap自动排序内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/qq_43687568/article/details/108506895 。
最后此篇关于关于Java HashMap自动排序的简单剖析的文章就讲到这里了,如果你想了解更多关于关于Java HashMap自动排序的简单剖析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有不同的结构,它们都包含一个 HashMap与 String作为键,但具有不同的值类型。例如,一个结构有一个类型为 HashMap 的成员, 另一个将有一个 HashMap 类型的成员, 等等。 我
我想制作一个包含学生姓名和科目的板,每个学生在每个科目中都有一个成绩(或者没有..他可以离开考试而不写,然后他的案子将是空的)。我只想使用 HashMap。我的意思是,它会是这样的: HashMap>
是否有内存和速度高效的方法来在 HashMap 中动态存储唯一键:值对? key 保证是唯一的,但它们的数量经常变化。插入和删除必须很快。 我所做的是包含有符号距离场的八叉树(非线性/完整)。八叉树经
有谁知道为什么选择通过 LinkedList 而不是另一个 Hashmap 来实现 HashMap 的存储桶。如果桶本身变成了 HashMap,那么 contains 或 get 的时间复杂度似乎是
我想创建一个具有嵌套结构的 HashMap,就像这个复杂的示例: { type: boy name: Phineas father: type: man
这个问题在这里已经有了答案: How do I create a global, mutable singleton? (7 个答案) 关闭 7 年前。 我想要一个可扩展的字典,将 Object 与
HashMap> hm = new HashMap>(); hm.put("Title1","Key1"); for(int i=0;i hm1 = new H
我必须修改当前代码以适应 Spring MVC。我有 HashMap hashmap = new HashMap(); request.setAttribute("dslrErrors", hashm
我正在尝试进行一些错误捕获。 错误应该检查数组的长度是否小于 2,并检查 HashMap 是否包含用户输入的键。 捕获的错误必须仅使用 if 语句,并且必须使用 .length() 方法,并且必须使用
在 stackoverflow 上提出另一个问题后,(Java- Why this program not throwing concurrent Modification exception)我开始
我有两个类,想使用 org.dozer.Mapper( http://dozer.sourceforge.net/ ) 将 Female 对象的属性映射到 Male 对象。 第一类是: public
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be
是否有任何方法可以检查 HashMap 是否包含一组特定的键(这些键是在数组中给出的)。当我尝试类似下面的代码时,它返回 false。 map.containsKey(arrayOf("2018-01
跟进我的问题:How To Access hash maps key when the key is an object 我想尝试这样的事情:webSearchHash.put(xfile.getPa
我有一个可扩展的 ListView ,对于每个 child ,我需要有 4 个“额外”或字符串或其他名称来调用它:- 子标题- 描述- 链接1- 链接2 跟着教程,创建 ListView 、不同的 p
我想确保这是正确的,因为如果不正确,它可能会破坏我的应用程序。 我有这个: private static HashMap> balance = new HashMap<>(); 如果我得到这样的值:
我想做以下事情: 为某个键查找Vec,并将其存储以备后用。 如果它不存在,则为键创建一个空的 Vec,但仍将其保存在变量中。 如何有效地做到这一点?自然地,我认为我可以使用 match: use st
我想做以下事情: 为某个键查找Vec,并将其存储以备后用。 如果它不存在,则为键创建一个空的 Vec,但仍将其保存在变量中。 如何有效地做到这一点?自然地,我认为我可以使用 match: use st
我想做以下事情: 为某个键查找Vec,并将其存储以备后用。 如果它不存在,则为键创建一个空的 Vec,但仍将其保存在变量中。 如何有效地做到这一点?自然地,我认为我可以使用 match: use st
我想做以下事情: 为某个键查找Vec,并将其存储以备后用。 如果它不存在,则为键创建一个空的 Vec,但仍将其保存在变量中。 如何有效地做到这一点?自然地,我认为我可以使用 match: use st
我是一名优秀的程序员,十分优秀!