Map,顾名思义,是一种映射的机制
在JAVA中,常用的有Hashtable,HashMap,LinkedHashMap,TreeMap
Hashtable的大部分方法都做了同步,是线程安全的,HashMap是非线程安全的;而且Hashtable不允许key/value为Null,而HashMap可以
1、HashMap
HashMap底层的数据结构还是数组,内存地址就是数组的下标,HashMap中的哈希算法如下:
static int hash(int h) {
h ^= (h>>>20)^(h>>>12);
return h^(h>>>7)^(h>>>4);
}
^表示异或操作,>>>表示无符号右移
我们来看几个例子,大家就知道哈希算法的精妙之处了:
a=32768
a的二进制:1000000000000000
a的哈希值:35080
a的哈希值的二进制:1000100100001000
a=65536
a的二进制:10000000000000000
a的哈希值:70161
a的哈希值的二进制:10001001000010001
a=524288
a的二进制:10000000000000000000
a的哈希值:561289
a的哈希值的二进制:10001001000010001001
a=123456789
a的二进制:111010110111100110100010101
a的哈希值:119583776
a的哈希值的二进制:111001000001011010000100000
不知道大家有没有看出来这里的精妙,哈希算法的精髓就是平均分布,我们可以看到哈希值的二进制中的1已经平均分布了,这里采用位运算符而不采用逻辑运算符,也是为了性能的提升。
自己可以动手试试了。
那么以上是得到了key的哈希值了,那么下面,我们如何通过key来获取value呢?
static int indexFor(int h,int lengh) {
return h&(lengh-1);
}
通过将哈希值与数组最后一个元素下标做与运算,得到的值就是value的数组下标,直接获取即可。
学过数据结构的都知道,哈希存在冲突问题,那么如何解决呢?
HashMap是采用数组+链表的方式来实现,所以同一下标有多个数据元素的时候就在该下标形成了一个链表。。。
后来的元素不断插入在链表头部
HashMap=ArrayList+LinkedList
HashMap默认初始化大小是16,负载因子是0.75,
负载因子=元素个数/内部数组总大小,其实就是填充率
HashMap的扩容,同样会进行数组的整体复制,所以扩容操作要注意
2、LinkedHashMap
由于HashMap的无序性,从来出现了LinkedHashMap
是基于元素进入集合的顺序或被访问的先后顺序排序
3、TreeMap
是基于元素的固有顺序
实现Comparable接口,重写compareTo()方法
set
set的实现都只是对map的一种封装而已
RandomAccess
所有基于数组的List都实现了此接口,而基于链表的没有,很简单,只有数组才能快速定位访问某个元素,而链表需要遍历
所以在代码中,当需要查找元素操作时,你可以先判断list instanceof RandomAccess,使用不同的遍历操作