- 浏览: 263209 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
cuiqi4016:
正在做json转换的功能,帮大忙了,感谢博主分享
java 通过反射获取泛型的类型 -
cxshun:
写得很好,感谢博主的分享
java 通过反射获取泛型的类型 -
joy3229233:
[url][/url][flash=200,200][/fla ...
(转)flex checkbox 选中 -
linkagebest:
盗版可耻。。。。。
(转)flex checkbox 选中 -
shuai0420:
...
flex数据绑定
Hashtable跟hashmap差不多,不过HashTable强制同步,是线程安全的。
HashSet<E>是通过内置的HashMap<E,object>来实现的,HashSet<E>中指定的元素类型E,本身就是key,每个元素的value是一个常量object,HashSet仅作一个集合管理,只有add contains remove等接口,没有get接口。
重点讨论下HashMap的结构。
HashMap维护了capacity个数的hash bucket(hash桶),这个是用数组实现的,即table[capacity],每个非空的hash bucket其实是一个映射链表的表头,即list head of entry,链表里面的每个entry负责一个具体key到value的映射。
每个hash bucket里元素,他们key值的hashcode可能不一样,即hash散列时是容许冲突的,但一样的是hashcode&(capacity-1),这个hashcode&(capacity-1)即他们所在的hash bucket在table[capacity]里的index,其实这就是hash散列的过程,顺便说下这个hashcode是key的hashcode经过变换之后得到的,这个index就是所谓的hash bucket index。
当然capacity也可以认为是元素的容量,因为理想的hash散列是一对一的,即没有散列冲突,一个hash bucket固定存储一个key到value的映射,后面可以看到容器维护的时候也是这么努力的,是否扩充容量是由元素的个数是否到了负载极限来决定的,而不是已填充的hash bucket的个数,这是表现之一。
有了这个概念之后再看hashmap的常见操作:
为一个元素在table[bucketIndex]里添加一个映射entry,如果超过threshold(Capacity * loadFactor),则扩展一倍,默认的容量是16,loderfactor是0.75,所以当元素个数达到12的时候,table容量扩充为32,依次64,128等
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex]; // 获取hash bucket里的entry链表表头
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
// new Entry<K,V>(hash, key, value, e) 构造里是这么写的:this.next = e,可见是前插法填充链表的。
if (size++ >= threshold)
resize(2 * table.length);
}
查找是否包含某个key的映射:比如 hm.add("ab");则hm.containsKey("ab")则true
public boolean containsKey(Object key) {
//空元素null特殊对待,貌似专门用一个object常量
Object k = maskNull(key);
//把k的hashcode再转换
int hash = hash(k);
//hashcode&(capacity-1)换的index
int i = indexFor(hash, table.length);
Entry e = table[i];
// 在entry链表里找key
while (e != null) {
//先验证key的hashcode,然后就是key的equals值
if (e.hash == hash && eq(k, e.key))
return true;
e = e.next;
}
return false;
}
按照这个过程分析hm.containsKey("ab"),过程就是通过"ab"的hashcode值找到hashbucket的entry链表表头,然后在里面逐个与"ab"比较equals,找到的话则返回true,否则false。其他的查找操作与这个过程大同小异,比如get(key);put(key,value)其实也有个类似的查找映射enty的操作。
public V put(K key, V value) {
K k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
if (e.hash == hash && eq(k, e.key)) {
//put另一个值得注意的地方:同一个key下增加,会把原来的value给覆盖掉
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, k, value, i);
return null;
}
同样如果是查找某个value,得依次遍历所有的hash bucket,并逐个与给定值进行equals,这个源码略去。
原创,转载请标注http://hi.baidu.com/heelenyc 欢迎交流指正。
再看hashtable。
大致上和hashmap是一样的,但可以肯定他们两不是一个人写的,实现细节有差别,包括hash散列函数,空值处理、代码风格等。
最重要的区别是在关键操作方法前多了一个synchronized同步的,这是出于线程安全而考虑的。下面以put函数为例
public synchronized V put(K key, V value) {
// Make sure the value is not null
//从这可以看出 hashtable不欢迎value==null的元素,hashmap对这个问题专门对待
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
//此处如果key为null,抛出异常
int hash = key.hashCode();
//跟hashmap的散列函数有区别
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
总结:
1、HashSet,HashMap,Hashtable 之所以"hash", 个人认为体现在:
首先、通过key的hashcde找到table[capability]里的hash bucket的过程,这是hash散列的过程,
其次、散列过程显然无法避免冲突,在元素个数不止一个的hash bucket通过链表查找key的过程,其实就是hash再探测的过程,显然java是通过链表来解决hash冲突的。
2、key的hashcode、key的equals方法和value的equals方法是hash容器操作的关键,所以当我们自定义hash容器的元素类的时候,特别要注意这两个方法的重写。用到的地方包括:
查找key是用key的hashcode找hash bucket,用key的equals找对应的entry;查找value是使用了value的equals来匹配的。
3、Hashtable和Hashmap在hash处理上大同小异,列举几点
区别一:hashtable不允许null的value,也没有考虑null的key,即在获取key的hashcode会抛出异常,hashmap碰到null的key都替换成一个常量object,它也可以容忍null的value
区别二:把key的hashcode散列到hash bucket的时候有区别
区别三:Hashtable强制同步,保证线程安全。
原创,转载请标注http://hi.baidu.com/heelenyc 欢迎交流指正。
待续,下次看下容器里的泛型编程和设计模式。
HashSet<E>是通过内置的HashMap<E,object>来实现的,HashSet<E>中指定的元素类型E,本身就是key,每个元素的value是一个常量object,HashSet仅作一个集合管理,只有add contains remove等接口,没有get接口。
重点讨论下HashMap的结构。
HashMap维护了capacity个数的hash bucket(hash桶),这个是用数组实现的,即table[capacity],每个非空的hash bucket其实是一个映射链表的表头,即list head of entry,链表里面的每个entry负责一个具体key到value的映射。
每个hash bucket里元素,他们key值的hashcode可能不一样,即hash散列时是容许冲突的,但一样的是hashcode&(capacity-1),这个hashcode&(capacity-1)即他们所在的hash bucket在table[capacity]里的index,其实这就是hash散列的过程,顺便说下这个hashcode是key的hashcode经过变换之后得到的,这个index就是所谓的hash bucket index。
当然capacity也可以认为是元素的容量,因为理想的hash散列是一对一的,即没有散列冲突,一个hash bucket固定存储一个key到value的映射,后面可以看到容器维护的时候也是这么努力的,是否扩充容量是由元素的个数是否到了负载极限来决定的,而不是已填充的hash bucket的个数,这是表现之一。
有了这个概念之后再看hashmap的常见操作:
为一个元素在table[bucketIndex]里添加一个映射entry,如果超过threshold(Capacity * loadFactor),则扩展一倍,默认的容量是16,loderfactor是0.75,所以当元素个数达到12的时候,table容量扩充为32,依次64,128等
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex]; // 获取hash bucket里的entry链表表头
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
// new Entry<K,V>(hash, key, value, e) 构造里是这么写的:this.next = e,可见是前插法填充链表的。
if (size++ >= threshold)
resize(2 * table.length);
}
查找是否包含某个key的映射:比如 hm.add("ab");则hm.containsKey("ab")则true
public boolean containsKey(Object key) {
//空元素null特殊对待,貌似专门用一个object常量
Object k = maskNull(key);
//把k的hashcode再转换
int hash = hash(k);
//hashcode&(capacity-1)换的index
int i = indexFor(hash, table.length);
Entry e = table[i];
// 在entry链表里找key
while (e != null) {
//先验证key的hashcode,然后就是key的equals值
if (e.hash == hash && eq(k, e.key))
return true;
e = e.next;
}
return false;
}
按照这个过程分析hm.containsKey("ab"),过程就是通过"ab"的hashcode值找到hashbucket的entry链表表头,然后在里面逐个与"ab"比较equals,找到的话则返回true,否则false。其他的查找操作与这个过程大同小异,比如get(key);put(key,value)其实也有个类似的查找映射enty的操作。
public V put(K key, V value) {
K k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
if (e.hash == hash && eq(k, e.key)) {
//put另一个值得注意的地方:同一个key下增加,会把原来的value给覆盖掉
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, k, value, i);
return null;
}
同样如果是查找某个value,得依次遍历所有的hash bucket,并逐个与给定值进行equals,这个源码略去。
原创,转载请标注http://hi.baidu.com/heelenyc 欢迎交流指正。
再看hashtable。
大致上和hashmap是一样的,但可以肯定他们两不是一个人写的,实现细节有差别,包括hash散列函数,空值处理、代码风格等。
最重要的区别是在关键操作方法前多了一个synchronized同步的,这是出于线程安全而考虑的。下面以put函数为例
public synchronized V put(K key, V value) {
// Make sure the value is not null
//从这可以看出 hashtable不欢迎value==null的元素,hashmap对这个问题专门对待
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
//此处如果key为null,抛出异常
int hash = key.hashCode();
//跟hashmap的散列函数有区别
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
总结:
1、HashSet,HashMap,Hashtable 之所以"hash", 个人认为体现在:
首先、通过key的hashcde找到table[capability]里的hash bucket的过程,这是hash散列的过程,
其次、散列过程显然无法避免冲突,在元素个数不止一个的hash bucket通过链表查找key的过程,其实就是hash再探测的过程,显然java是通过链表来解决hash冲突的。
2、key的hashcode、key的equals方法和value的equals方法是hash容器操作的关键,所以当我们自定义hash容器的元素类的时候,特别要注意这两个方法的重写。用到的地方包括:
查找key是用key的hashcode找hash bucket,用key的equals找对应的entry;查找value是使用了value的equals来匹配的。
3、Hashtable和Hashmap在hash处理上大同小异,列举几点
区别一:hashtable不允许null的value,也没有考虑null的key,即在获取key的hashcode会抛出异常,hashmap碰到null的key都替换成一个常量object,它也可以容忍null的value
区别二:把key的hashcode散列到hash bucket的时候有区别
区别三:Hashtable强制同步,保证线程安全。
原创,转载请标注http://hi.baidu.com/heelenyc 欢迎交流指正。
待续,下次看下容器里的泛型编程和设计模式。
发表评论
-
JVM内存管理:深入垃圾收集器与内存分配策略
2012-09-29 09:40 920转自http://icyfenix.iteye.com ... -
javaVM 内存管理
2012-09-29 09:18 1042转自http://icyfenix.iteye.com/blo ... -
使用J2SE API读取Properties文件的六种方法
2012-03-15 11:46 9441。使用java.util.Properties ... -
java设计模式 -Decorator
2012-03-01 16:05 970//抽象构件角色 abstract public c ... -
设计模式------Decorator
2012-03-01 14:29 807一、学习装饰着模式 1、定义及作用 该模式以对 ... -
正则表达式学习
2011-12-31 09:56 1068//正则表达式去掉中文 public static vo ... -
System.gc()
2011-06-24 17:40 1036最近在在翻看java的Garbage Collection,即 ... -
java gc(转)
2011-06-24 16:07 973<%@ page contentType="t ... -
hibernate
2011-06-24 11:29 01.hibernate lazy, inverse, casc ... -
详解spring事务属性(转)
2011-06-10 10:46 832Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我 ... -
spring心得(转)
2011-06-03 11:00 8421、spring原理 s ... -
实战Concurrent
2011-05-30 17:45 918编写多线程的程序一直都是一件比较麻烦的事情,要考虑很多事情,处 ... -
Memcached(转)
2011-05-30 17:32 958我对于Memcached的接触,还是在去年看了CSDN的一系列 ... -
动态创建代理(转)
2011-04-21 11:22 1056随着Proxy的流行,Sun把它纳入到JDK1.3实现了Jav ... -
代理模式(转)
2011-04-21 11:17 902代理模式是常用的Java 设计模式,它的特征是代理类与委托类有 ... -
工厂模式
2011-04-18 15:35 1069简单工厂,工厂方法和 ... -
java 通过反射获取泛型的类型
2011-03-24 13:34 32180jdk1.5开始支持泛型,所以我们有时需要把泛型里定义的对象的 ... -
java反射学习(转)
2011-03-22 15:51 1020Java提供了一套机制来动态执行方法和构造方法,以及数组操作等 ... -
java反射(转)
2011-03-22 15:29 973Java的反射机制是Java特 ... -
Quartz学习
2010-11-09 13:20 9331.与Spring集成 Spring中与quartz 的结合方 ...
相关推荐
HashSet作为Java集合框架中一个重要的非同步集合实现,它在JDK 7.0中的底层实现原理是基于HashMap来存储和操作数据的。下面就详细介绍HashSet的实现原理。 首先,HashSet是Set接口的一个实现类,它用于存储唯一性的...
之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也是说HashSet里面有一个HashMap(适配器模式)。因此本文将重点分析HashMap。 HashMap实现了Map...
也就是说:Java 集合实际上是多个引用变量所组成的集合,这些引用变量指向实际的 Java 对象。 4. HashMap 的存储实现 HashMap 的存储实现可以通过查看其 put(K key, V value) 方法的源代码来了解。该方法首先判断 ...
- **数组(Array)**:Java中的数组是基本的数据结构,可以直接声明和使用。 - **链表(Linked List)**:`java.util.LinkedList`提供了链表的实现。 - **栈(Stack)**:`java.util.Stack`是一个继承自`Vector`的类,实现...
Java集合专题总结:HashMap和HashTable源码...本文总结了HashMap和HashTable的源码学习和面试总结,涵盖了它们的存储结构、构造方法、get和put方法的源码分析、Hash表的特点和缺点、HashTable和HashMap的区别等内容。
本课件“数据结构 课件java版本”是基于Java编程语言来讲解这一主题的,旨在帮助学生和开发者深入理解数据结构的基本概念,并掌握用Java实现这些数据结构的方法。 在Java中,数据结构主要分为以下几类: 1. **数组...
5. HashSet的实现机理:HashSet的实现机理可以总结为:HashSet是基于HashMap实现的,HashSet的元素不重复机制是通过HashMap的put方法实现的,HashSet的其他方法都是通过调用HashMap的对应方法来实现的。 通过源码...
哈希映射(HashMap)和哈希集合(HashSet)都是基于哈希表的数据结构。哈希表通过哈希函数将键(Key)映射到数组的索引位置,以此实现快速查找。哈希冲突是哈希表必须面对的问题,cpp-sparsemap通过开放寻址法或链...
6. **集合**(Collection):Java的`java.util.Collection`接口是所有单值容器的父接口,包括`Set`和`List`。其中`ArrayList`和`HashSet`是最常用的实现。 7. **集合的变种:Set**(Set):不允许重复元素,`...
在Java编程语言中,HashMap和HashSet是两种常用的集合类,它们都依赖于哈希存储机制来提供高效的数据存取性能。这两个类分别实现了Map接口和Set接口,虽然它们的用途不同,但它们底层的实现原理有很强的关联性。本文...
Java容器集合(equals和hashCode+基础数据结构+ArrayList+Vector和LinkedList) Java容器集合是Java中的一种基础数据结构,用于存储和管理数据。其中,equals和hashCode方法是Java容器集合中两个非常重要的方法,...
在Java编程语言中,`Hashtable` 和 `HashMap` 都是用来存储键值对的数据结构。这两种数据结构虽然相似,但是在实现细节上存在显著差异。 1. **Hashtable**:作为 `Dictionary` 类的子类,`Hashtable` 是 Java 最早...
在Java编程语言中,HashSet和HashMap是两种非常重要的集合类,它们都位于`java.util`包下,分别用于存储不重复元素的集合和键值对的数据结构。本篇技术文档将深入剖析这两类数据结构的源码,帮助开发者理解其内部...
5. **集合(Collection)框架**:Java提供了一整套集合框架,包括List(ArrayList, LinkedList)、Set(HashSet, TreeSet)和Queue(LinkedList实现的Deque)等接口及其实现类。 6. **映射(Map)**:键值对存储,如...
Java 集合容器是 Java 语言中的一种数据结构,用于存储和操作数据。集合容器框架是 Java 中的一个重要组件,提供了一种统一的标准来存储和操作数据。下面是关于 Java 集合容器的知识点: 集合容器概述 集合容器是...
在Java编程语言中,HashMap是基于哈希表实现的数据结构,它是Map接口的一个具体实现,提供了高效的插入、删除和查找操作。HashMap不保证元素的顺序,允许null键和null值。HashMap的工作原理主要依赖于哈希算法,通过...
- **数据结构**:解释HashMap的数据结构是什么? - **put过程**:详细描述HashMap的put过程。 - **线程安全性**:解释为什么HashMap不是线程安全的? - **哈希碰撞处理**:HashMap是如何处理哈希碰撞的? - **get...
【Java 容器详解】 Java 容器是 Java 核心库的重要组成部分,它们提供了存储和管理对象的方式。常见的容器包括以下几类: 1. **集合接口**:主要有 Collection 和 Map 两大接口。 - **Collection**:代表一组不...