- 浏览: 622461 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (334)
- java core (12)
- struts2.x (2)
- spring (3)
- hibernate (8)
- jpa (6)
- maven (2)
- osgi (5)
- eclipse (4)
- struts2.x+spring2.x+hibernate 整合 (5)
- ebs (0)
- html (0)
- vaadin (1)
- css (0)
- jquery (0)
- javascript (0)
- svn (1)
- cvs (0)
- axas2.x (0)
- eclipse+maven (9)
- annotation (0)
- 基于OSGi的动态化系统搭建 (1)
- notenet (1)
- jboss eclipse (4)
- eclipse工具 (4)
- jdk1.6+maven3.0.3+nuxeo+svn+felix+cxf+spring+springDM (6)
- spring dm (1)
- Nexus介绍 (1)
- proxool listener (0)
- oracle (4)
- mysql (8)
- 搭建你的全文检索 (1)
- hibernatehibernatehibernate (0)
- cvsearchcvsearch (0)
- mycvseach (0)
- asdfasdfasdf (0)
- propertiey (0)
- hibernate annotation (0)
- libs (0)
- icam (2)
- start 数据库配置 (0)
- jboss (1)
- 让Eclipse启动时显示选择workspace的对话框 (1)
- table表头固定 (1)
- s2s3h4 (0)
- leaver (0)
- mycvsaerchddd (0)
- 关于jboss5.0.1部署 (4)
- bookmarks (0)
- PersistenceUnitDeployment (0)
- mycom (0)
- HKEY_CURRENT_USER = &H80000001 (0)
- syspath (1)
- css div (1)
- Dreamweaver CS5 (0)
- generate (0)
- mysql查看表结构命令 (1)
- LOG IN ERROR EMAIL TO SB (0)
- struts2 handle static resource (1)
- jsf (2)
- log4j (1)
- jbpm4.4 (2)
- down: jbpm4.4 (1)
- jstl1.2 (1)
- spring annotation (1)
- java design pattern (1)
- cache (1)
- ehcache (1)
- 11111 (0)
- myge (0)
- pom.xml (0)
- springquartz (0)
- OpenStack (9)
- hadoop (2)
- nginx (1)
- hadoop openstack (1)
- os (1)
- hadoop-2.6.0 zookeeper-3.4.6 hbase-0.98.9-hadoop2 集群 (5)
- hadoop2.7.0 ha Spark (2)
- tess (0)
- system (1)
- asdf (0)
- hbase (2)
- hbase create table error (1)
- ekl (1)
- gitignore (1)
- gitlab-ci.yml (1)
- shell (1)
- elasticsearch (2)
- Azkaban 3.0+ (1)
- centos用命令 (1)
- hive (1)
- kafka (1)
- CaptureBasic (0)
- CentOS7 (1)
- dev tools (1)
- README.md (1)
- Error (1)
- teamviewerd.service (1)
- scala (1)
- spark (1)
- standard (1)
- gitlab (1)
- IDEA (0)
- ApplicationContext (1)
- 传统数仓 (1)
- redis install (1)
- MYSQL AND COLUME (1)
- java版本选择 (1)
- hue (1)
- npm (1)
- es (1)
- 版本管理 (1)
- 升级npm版本 (1)
- git (1)
- 服务器参数设置 (1)
- 调大 IDEA 编译内存大小 (0)
- CentOS8安装GitLab (1)
- gitlab安装使用 (1)
最新评论
-
ssydxa219:
vim /etc/security/limits.confvi ...
ekl -
Gamehu520:
table中无数据
hbase 出现的问题 -
Xleer0102:
为什么都是只有问没有答,哭晕在厕所
hbase 出现的问题 -
jiajiao_5413:
itext table -
CoderDream:
不完整,缺com.tcs.org.demostic.pub.u ...
struts2.3.1.1+hibernate3.6.9Final+spring3.1.0+proxool+maven+annotation
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object val = map.get(key);
}
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}
static final int DEFAULT_INITIAL_CAPACITY = 16;
最大容量2的15次方+1;
static final int MAXIMUM_CAPACITY = 1 << 30;
默认加载因子:
static final float DEFAULT_LOAD_FACTOR = 0.75f;
内部实现的机制是用具有键值对格式的单个的entry数组实现:
- transient Entry[] table;
- static class Entry<K,V> implements Map.Entry<K,V> {
- final K key; //键
- V value; // 值
- Entry<K,V> next; //下一个
- final int hash; //哈西值
- /**
- * Creates new entry.
- */
- Entry(int h, K k, V v, Entry<K,V> n) {
- value = v;
- next = n;
- key = k;
- hash = h;
- }
- public final K getKey() {
- return key;
- }
- public final V getValue() {
- return value;
- }
- public final V setValue(V newValue) {
- V oldValue = value;
- value = newValue;
- return oldValue;
- }
- public final boolean equals(Object o) {
- if (!(o instanceof Map.Entry))
- return false ;
- Map.Entry e = (Map.Entry)o;
- Object k1 = getKey();
- Object k2 = e.getKey();
- if (k1 == k2 || (k1 != null && k1.equals(k2))) {
- Object v1 = getValue();
- Object v2 = e.getValue();
- if (v1 == v2 || (v1 != null && v1.equals(v2)))
- return true ;
- }
- return false ;
- }
- public final int hashCode() {
- return (key== null ? 0 : key.hashCode()) ^
- (value== null ? 0 : value.hashCode());
- }
- public final String toString() {
- return getKey() + "=" + getValue();
- }
- void recordAccess(HashMap<K,V> m) {
- }
- void recordRemoval(HashMap<K,V> m) {
- }
- }
当前的数组大小:
transient int size;
构造函数初始化:
设置初始化的容积和加载因子
- public HashMap( int initialCapacity, float loadFactor) {
- //初始化容积必须大于0
- 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);
- //找出一个数的平方大于当前给出的初始化容积,比如是初始化是10的话,那么最终的容积就是16
- int capacity = 1;
- while (capacity < initialCapacity)
- capacity <<= 1;
- this .loadFactor = loadFactor;
- threshold = ( int )(capacity * loadFactor);
- //用容积来初始化数组大小;size当前还是为0;
- table = new Entry[capacity];
- //初始化动作,可以留给子类实现,模板模式的应用
- init();
- }
这是一个hashcode的转换算法;他能够把对象的hashcode转换成为小于length-1的整数作为数组的下标;那么势必会出现重合
- static int hash( int h) {
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
- static int indexFor( int h, int length) {
- return h & (length-1);
- }
我们先看增加方法:
- public V put(K key, V value) {
- //判断键值是否为空;
- if (key == null )
- return putForNullKey(value);
- //得到hashcode
- int hash = hash(key.hashCode());
- //得到一个小于数组长度(取的是与操作)的下标
- int i = indexFor(hash, table.length);
- //在数组中找到该下标的entry值;
- //事实上entry也是一个链表,相对于LinkedList来说,他的entry是单向的
- for (Entry<K,V> e = table[i]; e != null ; e = e.next) {
- Object k;
- //如果存在键值是同一对象的entry,那么用新值覆盖旧值,不存在则再往下找,知道末尾
- if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
- V oldValue = e.value;
- e.value = value;
- e.recordAccess( this );
- return oldValue;
- }
- }
- //增加修改次数
- modCount++;
- //增加这个entry到该下标列表的首部
- addEntry(hash, key, value, i);
- return null ;
- }
- 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);
- //在这里增加了size;
- if (size++ >= threshold)
- resize(2 * table.length);
- }
如果key是null的话:
那么他可以不用通过hashcode定位数组中的队列下标-_-||事实上他也没有hashcode;规定在0位存放这个链表的头;可见在HashMap中是可以
存放null的key的;但是正因为其没有hashcode那么就只能存放一个元素,而不是像其他一样能存放多个;但是另外我们可见,你可以考虑把使
用的最多的值的键设置成为null,因为他是找到的最快的;
- private V putForNullKey(V value) {
- for (Entry<K,V> 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 ;
- }
上面说了存放了,下面我们再来看看如何取出来把:
- final Entry<K,V> getEntry(Object key) {
- //经过算法得到这个key对应的hashcode,可见hashcode是固定的对应,而不是随机的;如果是null的话为0,经过与操作还是0,直接
- //定位到table[0]否则查找出下标
- int hash = (key == null ) ? 0 : hash(key.hashCode());
- for (Entry<K,V> e = table[indexFor(hash, table.length)];
- e != null ;
- e = e.next) {
- Object k;
- //匹配这个key的hashcode和数值,可见不是同一的值其hashcode是可能一样的,否则如果是一一对应则没必要匹配key了
- if (e.hash == hash &&
- ((k = e.key) == key || (key != null && key.equals(k))))
- return e;
- }
- //没有找到,为空;
- return null ;
我们再来看看其容量是如何增长的:
- public void putAll(Map<? extends K, ? extends V> m) {
- //得到新增加进来的元素的个数
- int numKeysToBeAdded = m.size();
- if (numKeysToBeAdded == 0)
- return ;
- //如果新增加的元素个数大于原来容积*加载因子;可见我们必须要扩充容量了
- if (numKeysToBeAdded > threshold) {
- //那么我们增加的容量将是该新增元素个数+预留空间的总数
- int targetCapacity = ( int )(numKeysToBeAdded / loadFactor + 1);
- if (targetCapacity > MAXIMUM_CAPACITY)
- targetCapacity = MAXIMUM_CAPACITY;
- int newCapacity = table.length;
- //如果我们现在的表的容量小于新增加的容量,那么我们扩展两倍,如果还小,再扩大两倍,直到他的大于当前需要的容量
- while (newCapacity < targetCapacity)
- newCapacity <<= 1;
- if (newCapacity > table.length)
- resize(newCapacity);
- }
- //添置新的"家具"
- for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
- Map.Entry<? extends K, ? extends V> e = i.next();
- put(e.getKey(), e.getValue());
- }
- }
用新的容积开辟了一块足够大的存储空间,
- 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];
- transfer(newTable);
- table = newTable;
- threshold = ( int )(newCapacity * loadFactor);
- }
- 并且把家具从以前的“小房子”帮到了“大房子”
- void transfer(Entry[] newTable) {
- Entry[] src = table;
- int newCapacity = newTable.length;
- for ( int j = 0; j < src.length; j++) {
- //得到各个数组元素的链表的头
- Entry<K,V> e = src[j];
- if (e != null ) {
- src[j] = null ; //一定要把原来的“小房子”收拾好,方便垃圾回收;
- do {
- Entry<K,V> next = e.next;
- int i = indexFor(e.hash, newCapacity);
- e.next = newTable[i];
- newTable[i] = e;
- e = next;
- } while (e != null );
- }
- }
- }
新增,查找,都看过了,我们来看一下删除:
- public V remove(Object key) {
- Entry<K,V> e = removeEntryForKey(key);
- return (e == null ? null : e.value);
- }
- final Entry<K,V> removeEntryForKey(Object key) {
- //定位查找到链表表头;
- int hash = (key == null ) ? 0 : hash(key.hashCode());
- int i = indexFor(hash, table.length);
- Entry<K,V> prev = table[i];
- Entry<K,V> e = prev;
- while (e != null ) {
- Entry<K,V> 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是因为是单向链表,所以一旦找到的目标节点,无法通过该节点得到钱一个节点,就无法更改前
- 一个节点的指 //向,所以要保存prev
- prev = e;
- e = next;
- }
- return e;
- }
现在我们再看一下如何单独取到他的键值集合或者值集合:
- values实现了一个内部私有类;
- public Collection<V> values() {
- Collection<V> vs = values;
- return (vs != null ? vs : (values = new Values()));
- }
- //AbstractCollection<V> 把一些基本的curd委托给了iteartor,所以只需重载其获取iteartor的方法;
- private final class Values extends AbstractCollection<V> {
- //重载了iteartor
- public Iterator<V> iterator() {
- return newValueIterator();
- }
- public int size() {
- return size;
- }
- public boolean contains(Object o) {
- return containsValue(o);
- }
- public void clear() {
- HashMap. this .clear();
- }
- }
- 下面是该iteartor的获取:其中主要的是看看我们获取的value的collection是如何排序的;
- private abstract class HashIterator<E> implements Iterator<E> {
- Entry<K,V> next; // next entry to return
- int expectedModCount; // For fast-fail
- int index; // current slot
- Entry<K,V> current; // current entry
- HashIterator() {
- expectedModCount = modCount;
- //如果该HashMap有元素
- if (size > 0) { // advance to first entry
- Entry[] t = table;
- 然后把next和index都调至该table数组的链表头中不为空的地方;
- while (index < t.length && (next = t[index++]) == null )
- ;
- }
- }
- public final boolean hasNext() {
- return next != null ;
- }
- final Entry<K,V> nextEntry() {
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- Entry<K,V> e = next;
- if (e == null )
- throw new NoSuchElementException();
- //代表这个链表遍历完成了,需要开始遍历下一个table下标的链表了
- if ((next = e.next) == null ) {
- Entry[] t = table;
- //找到下一个不为空的table元素
- while (index < t.length && (next = t[index++]) == null )
- ;
- }
- current = e;
- return e;
- }
- public void remove() {
- if (current == null )
- throw new IllegalStateException();
- if (modCount != expectedModCount)
- throw new ConcurrentModificationException();
- Object k = current.key;
- current = null ;
- HashMap. this .removeEntryForKey(k);
- expectedModCount = modCount;
- }
- }
- ValueIterator :
- private final class ValueIterator extends HashIterator<V> {
- public V next() {
- return nextEntry().value;
- }
- }
这是我们会问加入我在这个value的collection中增加元素会出现什么样的情况呢,次序会不会打乱,对不起,AbstractCollection不存在add
的,iteartor也是不允许增加元素的;
对于来说keySet来说是同理的,不过因为key是不存在一样的,所以,我们不会返回collection而返回set,避免了重复key的出现;
发表评论
-
idea code
2019-10-14 15:35 324MNQ043JMTU-eyJsaWNlbnNlSWQiOiJN ... -
idea
2018-04-01 07:29 0http://idea.iteblog.com/ ... -
hashmap和hashtable
2012-12-20 15:04 972Java中hashmap和hashtable的区别 ... -
jdk schedule timer task
2012-12-19 10:33 844Implementing and scheduling a t ... -
synchronized
2012-11-01 14:29 01.把 synchronized (i) { 放在 while ... -
sdfasdfasdf
2012-10-19 18:12 0Hi, this is jar, it is really ... -
syspath
2012-09-21 13:42 1203Locale locale = Locale.getDefau ... -
gc---java
2012-06-28 10:38 0JVM内存模型中分两大块 ... -
JAVA_OPTS
2012-06-16 21:40 0set JAVA_OPTS=%JAVA_OPTS% -Xms5 ... -
daemon thread
2012-03-09 22:04 1175用户线程:是你自己写的,可以手工调用;守护线程(Daemon ... -
集合的区别总结
2012-03-07 10:32 1305hashMap和hashTable的几点区别 1. ... -
ClassLoader
2012-02-28 17:53 1215ClassLoader 类加载器 ... -
synchronized 规则
2012-02-27 11:05 0synchronized 方法控制对类 ... -
JDK1.6中文版的对HashMap
2012-02-27 10:28 1325以下是 JDK1.6 中 ... -
JDK1.6中文版的对HashMap
2012-02-27 10:27 965以下是 JDK1.6 中文版的对 HashMap 的具体介绍 ... -
Collection
2012-02-27 09:59 889线性表,链表,哈希表是常用的数据结构,在进行Java开发时,J ... -
until
2012-02-27 08:04 0Until 1 1. Be at the star ... -
Java Thread
2011-12-30 10:11 101961、线程概述 几乎所有的操作系统都支持同时运行 ...
相关推荐
HashMap之resize()方法源码解读 HashMap的resize()方法是HashMap中最核心的方法之一,该方法负责扩容HashMap的容量,以便存储更多的键值对。下面我们将对HashMap的resize()方法进行源码解读,了解其扩容机制和原理...
《HashMap面试题详解》 HashMap作为Java集合框架中的重要成员,是面试中常见的知识点,尤其在数据结构与算法、并发编程以及JVM内存管理等领域,HashMap的深入理解至关重要。本篇将围绕HashMap的相关面试题,从基础...
### hashMap和hashTable的区别 #### 一、简介与基本概念 `HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在...
在Java编程中,HashMap是一个非常常用的集合类,用于存储键值对数据。然而,它存在一个重要的特性,那就是线程不安全。理解这个问题并找到解决方案是每个Java开发者必须掌握的知识。 HashMap线程不安全的原因主要...
### HashMap与HashTable的区别详解 #### 引言 在Java编程中,`HashMap`与`HashTable`作为两种常用的数据结构,经常被用来存储键值对数据。尽管它们在功能上相似,但在实现细节、性能表现以及使用场景方面存在显著...
### HashMap介绍和使用详解 #### 一、HashMap的数据结构 HashMap是Java集合框架的一个重要组成部分,它实现了Map接口,能够存储键值对映射。在Java编程语言中,最基本的数据结构有两种:数组和引用(模拟指针)。...
在这个主题中,我们将深入探讨如何使用JNI处理HashMap、String等对象。 首先,让我们来理解JNI的基本结构。JNI接口提供了大量的函数,让本地方法(C/C++代码)能够创建、访问和修改Java对象。要使用JNI,你需要定义...
### 使用HashMap模拟网上购物车 #### 一、项目背景与目标 在本实验中,我们通过使用Java语言中的`HashMap`来模拟一个简单的网上购物车系统。该项目的主要目的是熟悉Java集合框架中的`HashMap`类,并了解如何利用它...
HashMap是Java编程语言中一个非常重要的数据结构,它属于集合框架的一部分,主要用于存储键值对(Key-Value)数据。HashMap在内部实现上基于哈希表,也称为散列表,它提供了一种快速查找、插入和删除数据的方法,...
### ibatis 使用 HashMap 解决 resultClass 映射 在日常的软件开发过程中,尤其是在处理数据库查询时,我们经常面临一个问题:如何优雅地处理那些未知或动态变化的列名及列数的情况?在这种情况下,传统的实体类...
Java HashMap 类详解 本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework ...
Java中的HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的高效存储和访问。HashMap基于哈希表(也称为散列表)原理工作,它允许用户通过键(Key)快速查找对应的值(Value)。在HashMap中,键和值...
哈希映射(HashMap)是Java编程语言中广泛使用的数据结构之一,主要提供键值对的存储和查找功能。HashMap的实现基于哈希表的概念,它通过计算对象的哈希码来快速定位数据,从而实现了O(1)的平均时间复杂度。在深入...
HashMap类在Java编程语言中是集合框架的一部分,它是一个基于哈希表的Map接口实现。HashMap提供了快速的插入、删除和查找操作,平均时间复杂度为O(1)。在这个压缩包“HashMap类.rar”中,包含的是易语言版本的...
### Java中HashMap, LinkedHashMap, TreeMap,HashTable的区别 在Java编程语言中,`Map`接口是集合框架中的一个重要组成部分,用于存储键值对。本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, ...
HashMap是Java编程语言中常用的集合类之一,它属于哈希表数据结构,提供key-value的存储方式,并且具有快速查询的特性。然而,HashMap本身并不保证元素的顺序,特别是当涉及到遍历或输出HashMap的内容时,顺序可能会...
哈希映射(HashMap)是Java编程语言中一个非常重要的数据结构,它在《简单的key value hashmap》中被提及,通常用于存储键值对(key-value pairs)。HashMap是Java集合框架的一部分,它提供了高效的查找、插入和删除...
《马士兵老师HashMap学习笔记详解》 HashMap是Java编程语言中常用的一种数据结构,它提供了键值对(key-value pair)的存储功能,是基于哈希表实现的。马士兵老师的HashMap学习笔记深入剖析了这一核心组件的工作...
在IT行业中,哈希表(HashMap)是一种高效的数据结构,它使用哈希函数将键(Key)映射到数组的特定位置,以便快速存取数据。Delphi是一种强大的Object Pascal编程语言,它提供了多种实现哈希表的方式。在这个特定的...