- 浏览: 62511 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
xuhang1128:
http://www.ihacklog.com/linux/m ...
Linux下安装memcached -
greatghoul:
常用的功能挺全面的。
vim使用技巧两篇
转自:http://www.cnblogs.com/huangfox/archive/2010/10/12/1848863.html HashMap 一般的线性表、树中,记录在数据结构中的相对位置是随机的,即和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在“比较”的基础上,查找的效率依赖于查找过程中所进行的比较次数。 理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。这里提到的对应关系称之为散列函数,常用的散列函数包括: Ø 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a•key + b,其中a和b为常数(这种散列函数叫做自身函数) Ø 数字分析法 Ø 平方取中法 Ø 折叠法 Ø 随机数法 Ø 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义 词。 1.1 创建:HashMap() HashMap 的实例有两个参数影响其性能:初始容量和加载因子。容量是 哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子 与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。 通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。 public HashMap(intinitialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity:" + initialCapacity); if (initialCapacity >MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 ||Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor:" + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; this.loadFactor = loadFactor; threshold = (int)(capacity *loadFactor); table = newEntry[capacity]; init(); } 注意: HashMap初始容量并非传入的initialCapacity的值,而是大于initialCapacity的2的最小指数: while (capacity < initialCapacity) capacity <<= 1; table = newEntry[capacity]; threshold等于实际容量capacity与loadFactor的乘积,是HashMap扩容的一个标准值。 HashMap是基于数组对键值对进行存放的 transient Entry[] table; Entry类属性包括: final K key; V value; Entrynext; final int hash; HashMap虽然是用数组进行存储,为什么还需要使用Entry next 属性对后续节点进行指定呢?这是因为在解决hash冲突的时候HasnMap采用的链表的方式。 1.2 添加数据:put(Object key , Object value) HashMap容许添加null值,如果该映射以前包含了一个该键的映射关系,则旧值被替换。 public V put(K key,V value) { //key为null的情况 if (key == null) return putForNullKey(value); //key不为null的情况 int hash = hash(key.hashCode()); int i = indexFor(hash,table.length); for (Entry 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++; addEntry(hash, key, value, i); return null; } 添加数据根据Key值是否为null分成两种情况。 当Key值为null时执行putForUnllKey( Object value) ; private V putForNullKey(Vvalue) { for (Entry e = table[0];e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(0, null, value, 0); return null; } 因为key值为null,无法通过现有的方式获取其散列值,因此取出数组中第一个Entry对象并遍历,但找到key值为null的Entry实例 后,将其value值替换成新的value值,然后返回。若没有找到key值为null的Entry实例,则添加一个Entry实例。 void addEntry(int hash,K key, V value, int bucketIndex){ Entrye = table[bucketIndex]; table[bucketIndex] = new Entry(hash, key, value, e); if (size++ >= threshold) resize(2 * table.length);//扩容,有兴趣可以更深入了解 } 默认其hash值为0,并且存放在数组的头部。当添加一个新Entry实例导致数组长度大于等于threshold,需要对数组进行扩容,并且对数组中所有元素重新hash,重新填充数组。 当key值不为null,首先获取key对象自身的hashCode,然后再对此hashCode做Hash操作: static int hash(int h) { // This function ensures that hashCodes that differ onlyby // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default loadfactor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h>>> 4); } 传入参数h及key对象自身的hashCode值。Hash完毕后与Entry对象数组的大小减1的值进行按位与操作(h & (length-1)),获得当前key要存储的数组的位置。 从上述内容可知key值到Entry数组的位置的过程:求自身hashCode;求hash值;与数组大小做与操作。这个过程可能会对不同的key 值产生相同的数组位置,这也就是常说的hash冲突。之前简单描述过HashMap是通过链表的方式解决这种冲突的,具体步骤如下所述。 获得key对应的位置后,获取该位置的Entry对象,使用next对其进行遍历,若存在hash值相等,且key值相等或equal的Entry对象,则将新的value覆盖该对象的value值。若不存在则在新增一个Entry实例,加入到该位置上链表的表头。示例: 图——(hash冲突)链表处理方式 假设之前位置5上有一个Entry实例(key5),现添加一个key9,假设key5和key9计算出来的位置都是位置5,并且key5不等于key9,那么就新增一个Entry(key9),并且将其next指向原位置链表的首元素(key5 Entry实例)。 1.3 通过key值获取value:get(Object key) 在6.2添加数据方法中,已经包括了get(Object key)的主要步骤。根据参数key是否为null分成两种情况。当key为null时,从Entry数组的第一个实例开始遍历(基于next),直至找 到key为null的Entry实例,获取其value值并返回。当key不为null时,获得其位置信息,进而获取该位置上的Entry实例,基于 next进行遍历,直至找到hash值相等,并且key相等或equal的Entry实例(e.hash == hash && ((k = e.key) == key ||key.equals(k))),获取其value值并返回。 public V get(Objectkey) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry e =table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k= e.key) == key || key.equals(k))) return e.value; } return null; } 1.4 移除数据:remove(Object key) final Entry removeEntryForKey(Object key) { int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash,table.length);//找到对应的位置 Entry prev = table[i]; Entry e = prev; while (e != null) { Entry next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) table[i] = next; else prev.next =next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; } 和get方法类似,凡是类似get的方法分两个步骤。步骤1:获取给定key的位置index;步骤2:获取Entry数组位置为index的 Entry实例,根据next进行遍历,比较key值和hash值。如果是get方法到此返回即可,不过remove则还需要修改next的值。 由于containKey(Object key)和get方法类似,不再重述。 1.5 注意 HashMap在遇到hash冲突时,使用的是链表的方式。 HashMap的initialCapacity和loadFactor会影响其添加、读取等动作的效率,在必要的时候可以进行调整、优化。 HashMap采用的数据进行存储,无容量限制。 HashMap线程不安全。
发表评论
-
JVM内存分析及导致内存溢出的不健壮代码及解决办法
2011-01-30 14:10 865关键字: Jvm , 内存 ... -
Java集合类--ArrayList
2011-01-30 13:59 780http://www.cnblogs.com/huangf ... -
Java集合类--LinkedList
2011-01-30 13:58 693http://www.cnblogs.com/huangf ... -
Java运行时绑定探讨
2011-01-30 13:46 577关键字: java , 多态 , 重载 , 重写 , 动 ... -
浅谈equals和hashcode
2011-01-30 13:45 600关键字: equals , hashcode 转 ... -
Junit4参数化测试
2011-01-30 13:45 639关键字: junit , 参数化 转自:http ... -
Java线程安全总结
2011-01-30 13:39 618关键字: java , 线程安全 , synchroni ... -
《软件开发沉思录》之对象健身操
2011-01-30 13:28 703关键字: 编码规范 最近看了一部分《软件开发沉思 ... -
Sun HotSpot JVM内存管理及垃圾收集
2011-01-30 13:21 1080关键字: jvm , 内存管理 , 垃圾收集 ...
相关推荐
总的来说,理解并熟练运用Java集合框架中的Map接口及其实现,对于JSP应用开发来说至关重要。正确选择和使用这些类可以帮助我们编写出高效、可维护的代码。在实际项目中,应根据具体需求和场景来决定使用哪种集合类型...
本文将深入探讨Java集合类的汇总,包括List、Set和Map这三大核心接口及其实现类。 首先,让我们从List接口开始。List是一种有序的集合,允许有重复元素,并且支持通过索引来访问元素。ArrayList和LinkedList是List...
综上所述,Java集合类如`List`、`ArrayList`、`Map`和`HashMap`提供了丰富的数据处理能力,而哈希函数及其应用则为数据安全和完整性校验提供了强大的支持。理解和掌握这些核心概念,对于编写高效、安全的Java应用...
Java 集合类 List-Set-Map 的区别和联系 Java 集合类 List、Set 和 Map 是 Java 语言中最基本的集合类,它们之间存在着紧密的联系和区别。在本文中,我们将对 Java 集合类 List、Set 和 Map 的区别和联系进行详细的...
在这个主题中,我们将深入探讨HashMap类,它是Java集合框架中的一个关键组件,特别是在标题“20-集合框架020-HashMap-1080P 高清-AVC20”和描述中所提到的内容。 HashMap是Java.util包中的一个类,它实现了Map接口...
理解并熟练运用Java集合体系中的List、Set、Map接口及其实现类,对于日常开发和面试来说至关重要,因为它们是许多Java框架和库的基础。在实际项目中,根据需求选择合适的集合类型可以提高代码的效率和可维护性。在...
### 精通Java集合框架——List, Set, Map #### 概述 Java集合框架是一种高度抽象且灵活的数据组织工具,它通过一系列接口来定义不同类型的数据容器,并提供了丰富的操作这些容器的方法。本文将深入探讨Java集合...
Java 集合类详解 Java 集合类是 Java 语言中的一种基本数据结构,用于存储和操作大量数据。集合类可以分为三大类:Collection、List 和 Set。 Collection 是集合框架中的根接口,提供了基本的集合操作,如 add、...
`Collection`接口是Java集合框架的核心接口之一,它是所有集合类的根接口。该接口定义了一组对象的通用操作,并且是`Set`和`List`接口的父接口。 **Collection接口的主要特点**: - 可以存放不同类型的数据。 - 子...
Java HashMap 类详解 本资源详细介绍了 Java 中的 HashMap 类...本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点,为大家提供了一个详细的 Java HashMap 类详解。
### Java集合排序及Java集合类详解 #### 一、集合框架概述 集合框架是Java编程语言的核心组件之一,用于组织和操作数据集。Java集合框架提供了多种数据结构,包括列表(List)、集(Set)和映射(Map),这些数据结构...
`www.pudn.com.txt`可能是提供资料来源的网站链接,这里主要关注的是`Java集合中HashMap的简单使用.txt`文件,它可能包含了关于如何在实际代码中运用`HashMap`的示例和解释。例如,如何创建`HashMap`,插入键值对,...
例如,它可能包含对ArrayList、HashMap等集合类的扩展功能,或者提供更便捷的日期格式化和比较功能。由于版本号为1.9.1,我们可以推断这个库可能已经历了多次迭代,以适应不断变化的开发需求和优化性能。 这两个库...
Java集合可以分为两大类:Collection和Map。 Java集合的类型 Java集合有多种类型,常见的有ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等。 * ArrayList:是一个基于数组的列表实现,支持随机...
根据给定文件的信息,我们可以总结出以下关于Java集合的相关知识点: ### 一、集合容器概述 #### 1. 什么是集合? 集合(Collection)是指在Java中用来存储、检索及操作一组对象的一种容器。它是一种高级的数据...
- `java.util`包中的ArrayList, LinkedList, HashMap等是常用的集合类,提供了存储和操作对象的方法。 - 集合框架包括List, Set, Queue, Map等接口,以及它们的实现类。 7. **多线程**: - Java内置对多线程的...
这篇7页的PDF文档“java集合类HashMap总结”可能是对HashMap类的深入解析,包括其原理、常用方法以及在实际开发中的应用。 HashMap的核心特性在于它的哈希函数,这个函数将键(key)转换为一个哈希码(hash code)...
"Java-Interview-超全集合github上评分最高的jiva面试题"就是一个这样的宝藏,它涵盖了Java编程语言、Git版本控制工具以及面试策略等多个方面的知识点。以下是这些内容的详细解析: 1. **Java基础** - **数据类型...
HashMap是Java编程语言中一种非常重要的数据结构,它属于Java集合框架的一部分,主要用来存储键值对(key-value pairs)。HashMap在内部实现上基于哈希表,提供了快速的插入、删除和查找操作,通常时间复杂度为O(1)...
### Java集合类性能分析 #### 一、Java集合框架概览 Java集合框架是一个非常重要的概念,它提供了处理数据集合的标准方法。集合框架的核心部分主要包括集合接口、抽象类以及具体的实现类。 - **集合接口**:Java...