Hashtable 的实现原理

Hashtable 的实现原理

【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种方式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/100466.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ba无标度网络python_python绘制BA无标度网络

    ba无标度网络python_python绘制BA无标度网络Copyright c 2017 东北大学软件学院学生 Allrightsres 文件名称 a py 作者 孔云 问题描述 问题分析 代码如下 importnetwor 导入建网络模型包 命名 neimportmatp pyplotasmp 导入科学绘图包 命名 mp BAscale freedegreene

    2026年1月28日
    1
  • Linux Shell 字符串拼接

    Linux Shell 字符串拼接http blog csdn net ysdaniel article details 6920866 转载于 https www cnblogs com deepblueme p 5164480 html

    2025年6月30日
    2
  • 在Laravel中使用数据库事务以及捕获事务失败后的异常

    在Laravel中使用数据库事务以及捕获事务失败后的异常

    2021年11月9日
    44
  • java inputstream和outputstream_string java

    java inputstream和outputstream_string javaInputStream读取流有三个方法,分别为read(),read(byte[]b),read(byte[]b,intoff,intlen)。其中read()方法是一次读取一个字节,效率是非常低的。所以最好是使用后面两个方法。/***读取流**@paraminStream*@return字节数组*@throwsException*/publicstaticbyte[…

    2025年12月2日
    5
  • java全排列递归算法_java排列组合代码实现

    java全排列递归算法_java排列组合代码实现一、排列1、计算公式如下:2、使用方法,例如在1,2,3,4,5中取3个数排列:3、全排列当m=n时,结果为全排列。例如1,2,3,4的全排列如下:4、代码实现求无重复数组的全排列 /** *循环递归获取给定数组元素(无重复)的全排列 * *@paramoriList原始数组 *@paramoriLen原始数组size *@paramarrayCombResult数组排列结果集,可传null或空Set *@parampreList记录排列参数

    2022年8月31日
    3
  • 手把手教你学dsp_大咖问答第13期:如何掌握DSP设计?顾卫钢博士在线为你解答…「建议收藏」

    手把手教你学dsp_大咖问答第13期:如何掌握DSP设计?顾卫钢博士在线为你解答…「建议收藏」本期邀请到了顾卫钢,参加电路城论坛第十三期大咖问答(8月4日-8月16日),本期将由顾卫钢为大家解答关于DSP设计方面的各种问题。大咖简介:顾卫钢,东南大学电气工程学院博士国内知名嵌入式培训专家,嵌入式产品技术顾问,2019年荣获TI大学计划卓越贡献奖。拥有近十年产品研发经验,近年来带领团队研发了具有代码自动生成功能、基于模型设计的实时数字控制器RTU-BOX、积木式电力电子功率组件等…

    2022年4月28日
    74

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号