HashMap是对数据结构中哈希表(Hash
创新互联公司是一家从事企业网站建设、成都做网站、网站设计、外贸营销网站建设、行业门户网站建设、网页设计制作的专业网站建设公司,拥有经验丰富的网站建设工程师和网页设计人员,具备各种规模与类型网站建设的实力,在网站建设领域树立了自己独特的设计风格。自公司成立以来曾独立设计制作的站点上千多家。
Table)的实现,Hash表又叫散列表。Hash表是根据关键码Key来访问其对应的值Value的数据结构,它通过一个映射函数把关键码映射到表中一个位置来访问该位置的值,从而加快查找的速度。这个映射函数叫做Hash函数,存放记录的数组叫做Hash表。
在Java中,HashMap的内部实现结合了链表和数组的优势,链接节点的数据结构是Entry
,每个Entry对象的内部又含有指向下一个Entry类型对象的引用,如以下代码所示:
static
class
Entry
implements
Map.Entry
{
final
K
key;
V
value;
Entry
next;
//Entry类型内部有一个自己类型的引用,指向下一个Entry
final
int
hash;
...
}
在HashMap的构造函数中可以看到,Entry表被申明为了数组,如以下代码所示:
public
HashMap()
{
this.loadFactor
=
DEFAULT_LOAD_FACTOR;
threshold
=
(int)(DEFAULT_INITIAL_CAPACITY
*
DEFAULT_LOAD_FACTOR);
table
=
new
Entry[DEFAULT_INITIAL_CAPACITY];
init();
}
在以上构造函数中,默认的DEFAULT_INITIAL_CAPACITY值为16,DEFAULT_LOAD_FACTOR的值为0.75。
当put一个元素到HashMap中去时,其内部实现如下:
public
V
put(K
key,
V
value)
{
if
(key
==
null)
return
putForNullKey(value);
int
hash
=
hash(key.hashCode());
int
i
=
indexFor(hash,
table.length);
...
}
hash是方法的参数,具体的计算你看下面的第49行
String hashCode=hash.........
第49行是计算hashCode,在第51行 调用 getCharacter(user,hashCode,null)这个方法,并将hashCode作为参数传进去,也就是传到了第37行 开始的方法里。
说白了就是你基础太差,看不懂。这其实就是个最简单的方法调用和参数传递。
hash是Object的一个方法 Object.hashCode() ; 返回值是int类型
1、Hash值有什么用?
HashMap、HashTable、HashSet,所以涉及到使用Hash值进行优化存储的地方,都会用到HashCode。HashCode是Key,这种计算为提高计算的性能。想想看,一般来说,数组算是比较快的集合类了吧,直接用index定位元素,简直就是O(1)的级别。但是添加元素就不这么乐观了。但是使用hash类的集合,添加元素,移动的元素少,只影响一小块,并且查找元素,由于hash值已经进行了定位分组,所以也会大大缩小涉及面,快速定位。
2、Hash值应该符合什么原则?
A、等幂性。不管执行多少次获取Hash值的操作,只要对象不变,那么Hash值是固定的。如果第一次取跟第N次取不一样,那就用起来很麻烦,需要记录当前是第几次操作,这种需要记录状态的事情,可不是什么好事。
B、对等性。若两个对象equal方法返回为true,则其hash值也应该是一样的。举例说明:若你将objA作为key存入HashMap中,然后new了一个objB。在你看来objB和objA是一个东西(因为他们equal),但是使用objB到hashMap中却取不出来东西。
C、互异性。若两个对象equal方法返回为false,则其hash值最好也是不同的,但这个不是必须的,只是这样做会提高hash类操作的性能(碰撞几率低)。
3、Hash值应该怎么计算?
A、简单计算就是组成成员的hash值直接相加即可。比如ObjectA有三个属性,propA、propB和propC,最直接的计算方式就是propA.hashcode+propB.hashcode+propC.hashcode。
B、但是如果遇到有顺序相关的怎么办?比如String类型是由char数组组成,并且这些数组是有顺序的。如果使用第一种计算方法,则“ABCD”和“BCDA”就会产生同样的hashCode,那么怎么办呢?最直接想到的办法就是加权,不同的index加不同的权值,这个权值的确定最直接的方法就是某个常数值的几次幂。比如为String的计算hash值为K^0*A.hashCode+K^1*B.hashCode+K^2*C.hashCode+K^3*D.hashCode。K的选择也有说法,最好不要是偶数,因为偶数的相乘会造成信息的丢失(乘以2就是左移1位,一旦溢出就会造成信息的丢失,这种计算会造成溢出后的值与某个看似不相关的数值得到的结果是一样的),所以最好是奇数,在这一点上比较推荐使用7,因为7=8-1=2^3-1,这样计算的时候,直接左移几位再进行一次普通的加减法即可(Java中常用的是31(32-1=2^5-1))。
Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。
简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
HASH主要用于信息安全领域中加密算法,他把一些不同长度的信息转化成杂乱的128位的编码里,叫做HASH值. 也可以说,hash就是找到一种数据内容和数据存放地址之间的映射关系
了解了hash基本定义,就不能不提到一些著名的hash算法,MD5 和 SHA1 可以说是目前应用最广泛的Hash算法,而它们都是以 MD4 为基础设计的。那么他们都是什么意思呢?
这里简单说一下:
1) MD4
MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。它适用在32位字长的处理器上用高速软件实现--它是基于 32 位操作数的位操作来实现的。
2) MD5
MD5(RFC 1321)是 Rivest 于1991年对MD4的改进版本。它对输入仍以512位分组,其输出是4个32位字的级联,与 MD4 相同。MD5比MD4来得复杂,并且速度较之要慢一点,但更安全,在抗分析和抗差分方面表现更好
3) SHA1 及其他
SHA1是由NIST NSA设计为同DSA一起使用的,它对长度小于264的输入,产生长度为160bit的散列值,因此抗穷举(brute-force)性更好。SHA-1 设计时基于和MD4相同原理,并且模仿了该算法。