集合相关问题

来源:互联网 发布:大淘宝联盟如何注册 编辑:程序博客网 时间:2024/06/05 14:10

有没有有顺序的map实现类?有哪几个?是如何保证它的顺序的?HashMap的随机存取和快速查找是如何实现的?

1.HashMap不是有序的;
2.TreeMap和LinkedHashMap是有序的(TreeMap默认升序,LinkedHashMap则记录了插入顺序)。
3.TreeMap的实现:
点击获取大神作品
4.LinkedHashMap的实现
点击获取大神作品
水平太菜导致精力有限,有序map留着以后看,目前着重研究了最经常用到的HashMap。
5.HashMap的实现:

1)HashMap的数据结构
数组寻址容易,插入删除困难。链表插入删除容易,寻址困难。不知道哪位牛人一开始提出了哈希表的概念,结合了数组和链表的优点。
哈希表有多种不同的实现方法,最常用的一种方法叫拉链法,我们可以理解为“链表的数组” ,如图:
这里写图片描述
一个长度为16的数组,存储的是每一条链表的头结点。那么此时一个很重要的问题需要解决,关键字和地址怎么进行映射。Hash表采用一个映射函数 f : key —> address 将关键字映射到该记录在表中的存储位置,这种映射关系称作为Hash函数。Hash函数的设计有很多方法,构造Hash函数时应尽量考虑关键字的分布特点来设计函数使得Hash地址随机均匀地分布在整个地址空间当中。我介绍一种比较好理解的:除留取余法

  如果知道Hash表的最大长度为m,可以取不大于m的最大质数p,然后对关键字进行取余运算,address(key)=key%p。

  在这里p的选取非常关键,p选择的好的话,能够最大程度地减少冲突,p一般取不大于m的最大质数。一般而言,p取值Hash表的长度m。例如上图中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。
  
HashMap的源码,其中参数initialCapacity就代表了该数组的长度:

public HashMap(int initialCapacity, float loadFactor) {        //初始容量不能<0        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal initial capacity: "                    + initialCapacity);        //初始容量不能 > 最大容量值,HashMap的最大容量值为2^30        if (initialCapacity > MAXIMUM_CAPACITY)            initialCapacity = MAXIMUM_CAPACITY;        //负载因子不能 < 0        if (loadFactor <= 0 || Float.isNaN(loadFactor))            throw new IllegalArgumentException("Illegal load factor: "                    + loadFactor);        // 计算出大于 initialCapacity 的最小的 2 的 n 次方值。        int capacity = 1;        while (capacity < initialCapacity)            capacity <<= 1;        this.loadFactor = loadFactor;        //设置HashMap的容量极限,当HashMap的容量达到该极限时就会进行扩容操作        threshold = (int) (capacity * loadFactor);        //初始化table数组        table = new Entry[capacity];        init();    }
  • 从源码中可以看出,每次新建一个HashMap时,都会初始化一个table数组。table数组的元素为Entry节点。
static class Entry<K,V> implements Map.Entry<K,V> {        final K key;        V value;        Entry<K,V> next;        final int hash;        /**         * Creates new entry.         */        Entry(int h, K k, V v, Entry<K,V> n) {            value = v;            next = n;            key = k;            hash = h;        }        .......    }
  • Entry是HashMap里面实现一个静态内部类,其重要的属性有 key , value,
    next,从属性key,value我们就能很明显的看出来Entry就是HashMap键值对实现的一个基础bean,我们上面说到HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。
    2)存取实现
    点击获取大神作品
    存取部分,本来已经码了好多,感觉写的不清晰,还是附上大神的作品吧。
    总之HashMap的源码设计的非常精彩,凝结了先贤们的智慧,读的非常过瘾。

集合相关问题:
1)HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
哈希表、哈希表&双向链表、多个子哈希表? 、数组、链表
2)HashMap和Hashtable的区别。
这里写图片描述
3)HashMap和ConcurrentHashMap的区别。
[大神作品]
ConcurrentHashMap的设计者Doug Lea,(来自百度百科)

说他是这个世界上对Java影响力最大的个人,一点也不为过。因为两次Java历史上的大变革,他都间接或直接的扮演了举足轻重的角色。2004年所推出的Tiger。Tiger广纳了15项JSRs(JavaSpecificationRequests)的语法及标准,其中一项便是JSR-166。JSR-166是来自于Doug编写的util.concurrent包。

4)HashMap和LinkedHashMap的区别。

对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。
LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。
注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。

5)HashMap是线程安全的吗?
不是,参考第3题。
6)ConcurrentHashMap是怎么实现线程安全的。
参考第3题。

原创粉丝点击