您的位置:首页 > 其它

Hashtable的实现原理

2014-03-25 09:29 204 查看



【IT168 技术文档】在仔细分析源代码之前,我们来看看Hashtable提供的一些接口方法。

public int size();

public boolean isEmpty() ;

public synchronized Enumeration keys();

public synchronized Enumeration elements();

public synchronized boolean contains(Object
value) ;

public synchronized boolean containsKey(Object
key);

public synchronized Object get(Object key);

public synchronized Object put(Object key, Object value) ;

public synchronized Object remove(Object key);

public synchronized void clear()
;

public synchronized void clear()
;

  上面的方法我就不一一介绍了,具体的用法也是很简单,相对大家对此也比较熟悉了。

Hashtable的用法

Hashtable 有2个构造函数

public Hashtable(int initialCapacity); //指定容量大小

public Hashtable() {

this(11); //默认的容量是11,为什么是11,而不是10呢?

}

Demo1

Hashtable sTable = new Hashtable();

sTable.put("wuhua","wuhua");

sTable.remove("wuhua");

sTable.clear();

上面是简单的用法。

Hashtable源代码解读

  在了解源代码之前,我们先来了解下一些java不常用的关键字。

transient

  当串行化某个对象时,如果该对象的某个变量是transient,那么这个变量不会被串行化进去。也就是说,假设某个类的成员变量是transient,那么当通过ObjectOutputStream把这个类的某个实例保存到磁盘上时,实际上transient变量的值是不会保存的。因为当从磁盘中读出这个对象的时候,对象的该变量会没有被赋值。 另外这篇文章还提到,当从磁盘中读出某个类的实例时,实际上并不会执行这个类的构造函数,而是读取这个类的实例的状态,并且把这个状态付给这个类的对象。

引用地址:http://blog.chinaunix.net/u/22516/showart.php?id=380029

  Transient 这个关键字很重要,来看下源代码里面有几处是用到这个关键字的。

private transient HashtableEntry table[];

private transient int count;

  源代码中只有上面两个字段的定义是用到的,但是这两个字段是用于存储Hashtable的容器字段,因此可以说Hashtable是不允许序列化的。

内部类

  Hashtable有2个内部类

  HashtableEntry -- 用于存放key-value,nextElement的类。

class HashtableEntry {

int hash;

Object key;

Object value;

HashtableEntry next;

}

  HashtableEnumerator 遍历的枚举类。

class HashtableEnumerator implements Enumeration {

boolean keys;

int index;

HashtableEntry table[];

HashtableEntry entry;

HashtableEnumerator(HashtableEntry table[], boolean keys) {

this.table = table;

this.keys = keys;

this.index = table.length;

}

public boolean hasMoreElements() {

if (entry != null)
{

return true;

}

while (index-- > 0)
{

if ((entry = table[index]) != null)
{

return true;

}

}

return false;

}

public Object nextElement() {

if (entry == null)
{

while ((index-- > 0) && ((entry = table[index]) == null));

}

if (entry != null)
{

HashtableEntry e = entry;

entry = e.next;

return keys ? e.key : e.value;

}

throw new NoSuchElementException(

/* #ifdef VERBOSE_EXCEPTIONS */

/// skipped "HashtableEnumerator"

/* #endif */

);

}

}

  代码写的是相当的简介。有一些比较技巧性的用法也是相当的不错,比如:

if (entry == null) {

while ((index-- > 0) && ((entry = table[index]) == null));

} 这段写的是相当的好,可见作者的功力,循环变量table

while (index-- > 0)

//循环变量,查看是否有下一个元素,

if ((entry = table[index]) != null)
{

return true;

}

}

  了解了Hashtable的数据存放格式,我们看看存放的关键逻辑

在put,remove,get方法中存在。

int index = (hash & 0x7FFFFFFF) % tab.length;

这样的函数,这个函数的意义上,根据散列值来获取对象的存储位置。

来欣赏下代码片段:

public synchronized Object get(Object key) {

HashtableEntry tab[] = table;

int hash = key.hashCode();

int index = (hash & 0x7FFFFFFF) % tab.length;

for (HashtableEntry e = tab[index] ; e != null ;
e = e.next) {

if ((e.hash == hash) && e.key.equals(key))
{

return e.value;

}

}

return null;

}

从上面的代码可以分析出。首先获取key的散列值,并且根据散列值进行key的Index定位

这里存在同一个index多个HashtableEntry 存在,所以才会有了next的变量,next就是存放相同位置不同key的实体。

下面再来看看Hashtable里面一个扩充容器的算法。

protected void rehash() {

int oldCapacity = table.length;

HashtableEntry oldTable[] = table;

int newCapacity = oldCapacity * 2 + 1;

HashtableEntry newTable[] = new HashtableEntry[newCapacity];

threshold = (int)((newCapacity * loadFactorPercent) / 100);

table = newTable;

for (int i = oldCapacity
; i-- > 0 ;) {

//循环遍历oldTable的对应的实体,并且遍历对应的实体的没一个对象,进行

//重新分配index,再进行保存

for (HashtableEntry old = oldTable[i] ; old != null ;
) {

HashtableEntry e = old;

old = old.next;

int index = (e.hash & 0x7FFFFFFF) % newCapacity;

e.next = newTable[index]; //e 的next 指向当前索引

newTable[index] = e; //

}

}

}

for (HashtableEntry old = oldTable[i] ; old != null ;
)

这段的用法很奇怪,我以前没有使用过,上面的代码等同于

HashtableEntry old = oldTable[i];

Whild(old != null){

...............................

...............................

}

不过个人比较习惯使用第2种方式

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: