我们到底能走多远系列(27)

public V put(K key, V value) {(key == null )return putForNullKey(value);int hash = hash(key);int i = indexFor(hash, table. length);for (Entry<K,V> e = table [i]; e != null; e = e.next) {Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e. value;e. value = value;e.recordAccess( this);return oldValue;}}modCount++;// 拆出去的方法,利于子类的自定义实现addEntry(hash, key, value, i);return null ;}void addEntry( int hash, K key, V value, int bucketIndex) {if ((size >= threshold ) && (null != table[bucketIndex])) {// 扩大2倍resize(2 * table. length);hash = ( null != key) ? hash(key) : 0;bucketIndex = indexFor(hash, table.length);}createEntry(hash, key, value, bucketIndex);}public V get(Object key) {if (key == null )return getForNullKey();Entry<K,V> entry = getEntry(key); }final Entry<K,V> getEntry(Object key) {int hash = (key == null) ? 0 : hash(key);for (Entry<K,V> e = table [indexFor(hash, table.length )];e != null;e = e. next) {Object k;if (e.hash == hash &&((k = e. key) == key || (key != null && key.equals(k))))return e;}return null ;}

一些理解:

1,从上面的代码看map的结构基本相同,我们会注意到,服务器空间,如果在插入数据的时候,网站空间,这些数据平均的分配到数组上,也就是说没有产生链表的数据结构,那么在取得这个数据是通过地址查询的,如果出现最坏的情况,那就是大多或所有的数据的hashcode都相同,导致所有的数据都存在某个数组下标下的链表结构上,那么这个链表会变得很大,如此每次查询最坏的是遍历查询,也就失去的map的意义。

所以在操作的时候,链表中的元素越多,效率越低,因为要不停的对链表循环比较。所以,一定要哈希均匀分布,尽量减少哈希冲突,减少了哈希冲突,就减少了链表循环,就提高了效率。

这个问题就肯呢过会引起:Hash Collision DoS

的描述:

无论你用JSP,PHP,Python,Ruby来写后台网页的时候,在处理HTTP POST数据的时候,美国服务器,你的后台程序可以很容易地以访问表单字段名来访问表单值,就像下面这段程序一样:

1

2

$usrname = $_POST[‘username’];

$passwd = $_POST[‘password’];

这是怎么实现的呢?这后面的东西就是Hash Map啊,所以,我可以给你后台提交一个有10K字段的表单,这些字段名都被我精心地设计过,他们全是HashCollision,于是你的Web Server或语言处理这个表单的时候,就会建造这个hash map,于是在每插入一个表单字段的时候,都会先遍历一遍你所有已插入的字段,于是你的服务器的CPU一下就100%了,你会觉得这10K没什么,那么我就发很多个的请求,你的服务器一下就不行了。

举个例子,你可能更容易理解:

如果你有n个值—— v1, v2, v3, … vn,把他们放到hash表中应该是足够散列的,这样性能才高:

0 -> v21 -> v42 -> v1……n -> v(x)

但是,这个攻击可以让我造出N个值—— dos1, dos2, …., dosn,他们的hash key都是一样的(也就是Hash Collision),导致你的hash表成了下面这个样子:

0 – > dos1 -> dos2 -> dos3 -> …. ->dosn1 -> null2 -> null……n -> null

于是,单向链接就这样出现了。这样一来,O(1)的搜索算法复杂度就成了O(n),而插入N个数据的算法复杂度就成了O(n^2),你想想这是什么样的性能。

2,还注意到,map中的数组是有长度的,当放入的数据足够多,就是满足了

HashMap 的 size>=threshold

而这两个方法是很耗时,因为他们要对每一个数据重新计算hashcode,重新计算在数组中的位置。

关于LinkedHashMap:

有时候在实现业务的时候我们需要一个有序的Map,可能会想到LinkedHashMap

事实上 它继承了HashMap,自己维护了一个双向链表,以保存数据的顺序。

看一下他的增加数据的方法:

人的一辈子唯一做的就是,不断地用你手中

我们到底能走多远系列(27)

相关文章:

你感兴趣的文章:

标签云: