java性能优化读书笔记之三《程序优化===集合优化(Map)》
2015-12-22 16:51
597 查看
1. 数据结构
参考博客数据结构map概述
map的数据结构为key(键)和value(值)键值对的模式。内部原理是基于数组与单向链表的。其操作是对数组和单向链表进行增加、删除、修改、遍历。
HashMap和Hashtable不同之处在于Hashtable允许key或者value为空,再者Hashtable是线程安全的。
2. hashMap结构图(哈希表)
纵向为数组、横向为单向链表
使用场景
1、需要线程安全的,请使用Hashtable。
2、允许key或者value为空请使用Hashtable。
3、追求程序性能的,是使用HahsMap
3. HashMap源码分析
了解源码之前,请先学习一下数据结构中的哈希表以及算列法。数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表,哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法——拉链法,我们可以理解为“链表的数组。
HashMap无惨构造方法
/** * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ public HashMap() { //loadFactor 负载因子默认为 0.75f this.loadFactor = DEFAULT_LOAD_FACTOR; //threshold 临界值 = 默认初始容量 * 负载因子 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); //默认初始容量(16) table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); }
从源码获取HashMap的容器容量大小为16, 扩容的临界值为12。
hashMap的put方法
* Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { //key可以为空 if (key == null) return putForNullKey(value); //取得key的hashCode int hash = hash(key.hashCode()); //取得元素在数组中的位置或者是内存中的位置 int i = indexFor(hash, table.length); //解决hash冲突,新插入的元素的数组位置如果已经被其他元素占用了,那么就使用单向链表。占用的元素链表下一个指向新插入的元素 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } //修改记录统计 modCount++; //hash不冲突,新元素则添加到指定的数组位置 addEntry(hash, key, value, i); return null; }
根据散列法获取数组的位置
/** * Returns index for hash code h. */ static int indexFor(int h, int length) { //等同于h%length,但是不等效。h%length需要调用cpu计算。效率更低 return h & (length-1); }
HashMap数组扩容
/** * Adds a new entry with the specified key, value and hash code to * the specified bucket. It is the responsibility of this * method to resize the table if appropriate. * * Subclass overrides this to alter the behavior of put method. */ void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; //在指定的数组下标位置添加新元素 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); //判断添加元素后的容器容量大于临界值。则需要数组扩容 if (size++ >= threshold) //扩容的容器容量= 2 * 数组长度 resize(2 * table.length); } /** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //扩容后新的数组 Entry[] newTable = new Entry[newCapacity]; //将旧的数据内容copy扩容后新的数组 transfer(newTable); table = newTable; //重新计算临界值 = 数组长度 * 负载因子 threshold = (int)(newCapacity * loadFactor); }
4. map优化点
1、负载因子本身就是在空间和时间之间的折衷。当我使用较小的负载因子时,虽然降低了冲突的可能性,使得单个链表的长度减小了,加快了访问和更新的速度,但是它占用了更多的空间,使得数组中的大部分空间没有得到利用,元素分布比较稀疏,同时由于Map频繁的调整大小,可能会降低性能。但是如果负载因子过大,会使得元素分布比较紧凑,导致产生冲突的可能性加大,从而访问、更新速度较慢。所以我们一般推荐不更改负载因子的值,采用默认值0.75.HashMap优化代码
暂无,后续添加
相关文章推荐
- 深入理解PHP7内核之FAST_ZPP
- Flex 性能优化常用手法总结
- oracle 性能优化建议小结
- Lua性能优化技巧(一):前言
- Lua性能优化技巧(五):削减、重用和回收
- Lua性能优化技巧(三):关于表
- Lua性能优化技巧(四):关于字符串
- MySQL性能优化 出题业务SQL优化
- PowerShell脚本性能优化技巧总结
- SQL SERVER性能优化综述(很好的总结,不要错过哦)第1/3页
- MySQL Index Condition Pushdown(ICP)性能优化方法实例
- Ajax无刷新分页的性能优化方法
- dedecms负载性能优化实例,三招让你的dedecms快10倍以上第1/2页
- 如何减少浏览器的reflow和repaint
- javascript日期处理函数,性能优化批处理
- JavaScript 性能优化小结
- JQuery教学之性能优化
- jQuery 性能优化手册 推荐
- jQuery 性能优化指南(2)
- JQuery性能优化的几点建议