Java的集合类以及hashMap的实现原理

来源:互联网 发布:当今世界网络强国 编辑:程序博客网 时间:2024/05/21 11:04
Java集合类
Collection
List
ArrayList
LinkedList
Vector
Set
HashSet
LinkedHashSet
SortedSet
TreeSet
Map
HashMap
HashTable
WeakHashMap

Collection是所有集合类的根接口,其被继承产生了2个接口,分别是List和Set。
List是无序的、可重复,提供了按照索引访问的方式,查询速度快,往集合里面添加或者删除元素的时候会伴随着后面数据的移动,所以插入删除速度会慢
Set是有序的、不可重复的
Map:K-V键值对,一个key只能对应一个value,一个value可以对应多个key

遍历方式
Iterator
foreach
for循环
keySet(针对map)

ArrayList和LinkedList
ArrayList实现了基于动态数组的数据结构,LinkedList是基于链表的数据结构
对于访问查询来说,arrayList可以快速的定位,linkedList需要移动指针,速度相对较慢
对于添加和删除操作,arrayList会导致后面元素的移动,速度相对较慢;linkedList只需要将之前的链断掉,重新建立起新的链,速度相对较快

HashMap和TreeMap
HashMap是通过hashCode进行的查找;TreeMap保持着某种固定的顺序
在Map中添加,删除操作,用hashmap比较好,但是要按照自然顺序或者自定义顺序来得到结果,treeMap比较好
同样做测试:
在HashMap中,同样的值的map,顺序不同,equals时,false;
而在treeMap中,同样的值的map,顺序不同,equals时,true,说明,treeMap在equals()时是整理了顺序了的。

HashTable与HashMap
Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。
HashMap允许存在一个为null的key,多个为null的value 。
hashtable的key和value都不允许为null。

在java语言中,最基本的数据结构有2种,一个是数组,一个是模拟指针,所有的数据类型都可以用这两种数据结构来构造,hashMap也不例外,hashMap采用了“链表散列”的数据结构,也就是数组和链表的结合体
能够看出来hashMap的底层实际上是数组,不过数组中的元素又是链表。初始化hashMap的时候,就是新创建了一个数组

hashMap的存储实现
根据源码我们可以看到,当我们往hashMap中put元素的时候,首先会根据key的hashCode计算出hash值,根据hash值就能确定出这个元素放在数组中的什么位置(下标),如果这个位置已经有元素存在了,那么这个位置上的元素就会以链表的形式进行存储,即新添加的元素放在链表头,之前的元素放链表尾,如果这个位置没有元素存在,那直接就放在这个位置

从hashMap取元素的时候,辉县根据key的hashCode,找到所在的位置,然后通过equals方法来在链表中找到对应的元素

我们可以看到在HashMap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。前面说过HashMap的数据结构是数组和链表的结合,所以我们当然希望这个HashMap里面的元素位置尽量的分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表,这样就大大优化了查询的效率。
   对于任意给定的对象,只要它的 hashCode() 返回值相同,那么程序调用 hash(int h) 方法所计算得到的 hash 码值总是相同的。我们首先想到的就是把hash值对数组长度取模运算,这样一来,元素的分布相对来说是比较均匀的。但是,“模”运算的消耗还是比较大的,在HashMap中是这样做的:调用 indexFor(int h, int length) 方法来计算该对象应该保存在 table 数组的哪个索引处。indexFor(int h, int length) 方法的代码如下:
Java代码  
  1. static int indexFor(int h, int length) {  
  2.     return h & (length-1);  
  3. }  
 
   这个方法非常巧妙,它通过 h & (table.length -1) 来得到该对象的保存位,而HashMap底层数组的长度总是 2 的 n 次方,这是HashMap在速度上的优化。在 HashMap 构造器中有如下代码:
Java代码  
  1. int capacity = 1;  
  2.     while (capacity < initialCapacity)  
  3.         capacity <<= 1;  
   这段代码保证初始化时HashMap的容量总是2的n次方,即底层数组的长度总是为2的n次方。
当length总是 2 的n次方时,h& (length-1)运算等价于对length取模,也就是h%length,但是&比%具有更高的效率。



原创粉丝点击