HashMap和Hashtable 之原代码详解 (本人原创)

graygu 2007-08-27 11:09:09
Hashtable从JDK1.0就已经有了, 所以让我们先来看看它是怎么工作, 然后有浅入深, 来研究HashMap的原理, 以及两者的不同点.

Hashtable有几个主要的字段, 如下,

/**
* The hash table data.
*/
private transient Entry[] table;

/**
* The total number of entries in the hash table.
*/
private transient int count;

/**
* The table is rehashed when its size exceeds this threshold. (The
* value of this field is (int)(capacity * loadFactor).)
*
* @serial
*/
private int threshold;



其中最重要的就是那个table数组了. 它就是整个hashtable的基本数据结构! 在来看一下这个字段
private transient Entry[] table;

可以看到, hashtable的基本数据结构就是, 一个包涵Entry类的二维数组. 而这个Entry类是hashtable的内在类, 它其实是一个单向链, 让我们详细分析一下.


private static class Entry<K,V> implements Map.Entry<K,V> {
int hash;
K key;
V value;
Entry<K,V> next;
...
...

看到这里有没有想到学校里教的数据结构原理这门课呢? Entry类就是定义了一个很简单的单向链结构, 它里面包括key, value和下个Entry类的对象next.
在这里我在强调一下, hashtable的数据结构就是一个包涵单向链的二维数组.

(未完待续)
...全文
1580 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
fgmailbox 2007-09-03
  • 打赏
  • 举报
回复
good
junhe102 2007-09-02
  • 打赏
  • 举报
回复
结贴了也要顶
graygu 2007-08-31
  • 打赏
  • 举报
回复
多谢大家捧场! 结贴!
vanrest 2007-08-30
  • 打赏
  • 举报
回复
MARK!!!
xuelong_zl 2007-08-29
  • 打赏
  • 举报
回复
有意思,这样的精神喜欢
wipe_tear 2007-08-28
  • 打赏
  • 举报
回复
暂时没时间,晚上回来和你一起讨论,嘿嘿,你说的一而不一定对哦 :)
graygu 2007-08-28
  • 打赏
  • 举报
回复
看完了hashtable, 我们在来看看hashMap
hashMap可以算作是hashtable的升级版本, 最早从1.2开始有的.
整体上hashMap对hashtable类优化了代码. 比如说, 消除了hardcoding, 增加了code reuse等等.
但是, 两者之间最主要的不同有两点.
1. hashMap的读写是unsynchronized, 在多线程的环境中要注意使用
而hashtable是synchronized
这两者的不同是通过在读写方法上加synchronized关键字来实现的.

hashMap
public V put(K key, V value)
public V get(Object key)

hashtable
public synchronized V get(Object key)
public synchronized V put(K key, V value)

可能有人问, 能synchronized, 能线程安全好啊. 为什么不要呢?
这里其实还是一个效率的问题. 对于线程安全的方法, 系统要进行加锁, 减锁操作. 性能会有很大的影响. 由于很多程序是在单线程或者说是线程安全的情况下工作的, 所以用synchronized就显得多余了.

3. 第二个不同是hashMap可以放空值, 而hashtable就会报错.
hashMap
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);

hashtable
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}

(本文结束)
wst781229 2007-08-28
  • 打赏
  • 举报
回复
不错呀!!!!
syhan 2007-08-28
  • 打赏
  • 举报
回复
分析的挺好
www_dragon_com 2007-08-28
  • 打赏
  • 举报
回复
等下期....
snow8261 2007-08-28
  • 打赏
  • 举报
回复
不错!
houfeng_dao 2007-08-28
  • 打赏
  • 举报
回复
Thanks a lot
graygu 2007-08-27
  • 打赏
  • 举报
回复
(未完待续)
wuhaozhiyuan 2007-08-27
  • 打赏
  • 举报
回复
支持下
sonyejin 2007-08-27
  • 打赏
  • 举报
回复
HashMap有看头,支持
graygu 2007-08-27
  • 打赏
  • 举报
回复
接下来让我们来看看hashtable的构造器是长的什么样的.

最长用的

public Hashtable() {
this(11, 0.75f);
}

这个构造器调用了另外一个构造器

public Hashtable(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal Load: "+loadFactor);

if (initialCapacity==0)
initialCapacity = 1;
this.loadFactor = loadFactor;
table = new Entry[initialCapacity];
threshold = (int)(initialCapacity * loadFactor);
}

细读代码后, 我们发现这个构造器构造了table字段和threshold. Table前面已经详细讲了, 那么这个threshold又是什么东东呢?
其实这个threshold对hashtalbe的性能影响是很大的! 因为table是个数组, 如果在hashtable中保存的实体大于一定的数量后, 对数据的读写就会有很慢, 那是因为, 很多数据都保存在entry类的单向链中, 每次读写都要比对链中所有的数据, 链越长读写就越慢.
所以当数据容量大于threshold的时候, hashtable就会做rehash(), rehash把table的容量扩大一倍, 再把从前在table里的数据统统搬回新的table. 这样的一个过程, 开销是多么的大呀.
threshold = (int)(initialCapacity * loadFactor);
Hashtable类提供了构造涵数, 用户可以自定, intitialCapacity和loadFactor. 对于那些大概知道容量的hashtable, 用户应该自定intitialCapacity. 这样的话, 就可以省去一大笔rehash的开销.
cgx777 2007-08-27
  • 打赏
  • 举报
回复
xie xie 完了?
zdjray 2007-08-27
  • 打赏
  • 举报
回复
支持下~~
codeartisan 2007-08-27
  • 打赏
  • 举报
回复
记号一个
hoperun 2007-08-27
  • 打赏
  • 举报
回复
up
加载更多回复(4)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧