Map接口-旗下HashMap,HashTable,SortedMap,TreeMap,HashTable,ConcurrentHashMap

来源:互联网 发布:can总线通讯协议 编程 编辑:程序博客网 时间:2024/05/20 06:41
       标题有点长哈,不过这也说明我们的干货也多(哈哈)开玩笑的,这里只是讲一些个人的理解,希望对有关知识感兴趣的童鞋有些许帮助     1,没错,他们都是键值对     2,HashMap熟悉吧,刚学时经常用这个Map map=new HashMap();没错,他就是我们经常用来实例化Map接口的东西(单线程),简单,好用     3,上面括号大家想必注意到了,单线程,那么传说中并发这种高大上场合我们会使用哪种map呢?好激动,那就是HashTable,感觉好厉害的样子。其实不然,他所做的工作有点简单,就是在其中的方法块上加上synchronized这个同步锁,有并发编程知识的童鞋肯定知道,这玩意在些低并发场合还行,可上不了高并发的舞台。那么高并发情况下,我们通常会选用谁呢?yes,ConcurrentHashMap,加强版HashTable,对map键值对的各种操作进行了更细化的同步处理,每次操作没有像HashTable那么粗暴,至于如何细化,下文会慢慢道来~ 二,功能挺全的,讲完功能,再来深入一些类的细节。       HashMap,这里就把函数列举一下吧(之所以列举,是因为虽然后面的那些看似高大上的东西其实它们的功能函数一样,废话,不然还是Map接口旗下~~~)      void clear( ) 从此映射中移除所有映射关系(可选操作)      boolean containsKey(Object k)如果此映射包含指定键的映射关系,则返回 true      boolean containsValue(Object v)如果此映射将一个或多个键映射到指定值,则返回 true。      Set entrySet( )返回此映射中包含的映射关系的 Set 视图      boolean equals(Object obj)比较指定的对象与此映射是否相等      Object get(Object k)返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。       int hashCode( )返回此映射的哈希码值       boolean isEmpty( )如果此映射未包含键-值映射关系,则返回 true。       Set keySet( )返回此映射中包含的键的 Set 视图。       Object put(Object k, Object v)将指定的值与此映射中的指定键关联(可选操作)。       void putAll(Map m)从指定映射中将所有映射关系复制到此映射中(可选操作)       Object remove(Object k)如果存在一个键的映射关系,则将其从此映射中移除(可选操作)       int size( )返回此映射中的键-值映射关系数。       Collection values( )返回此映射中包含的值的 Collection 视图       这里面我想解释的几个函数是:Set keySet( ), Collection values( ),Set entrySet( ),其实我这么放的顺序就表明一定的意思,hashmap.keySet()返回这个map的key的set集合,hashmap.values()返回的是值的collection,那么为什么还要第三者啊,前两个不是已经满足我们要遍历map的需求了吗?我要说,显然第三者用着更爽!怎么用?举个栗子,Set<Map.Entry<String,String>> entries=hashmap.entrySet();    Iterator iterator=entries.iterator();    while(iterator.hasNext()){ //假如hashmap里面的key和value都是string Map.Entry<String,String> entry=iterator.next(); String key=entry.getKey(); Sring value=entry.getValue();}     是不是用着很爽?这种遍历比你先找到key再得值爽多了吧?你甚至可以不需要知道值。     HashTable,好吧,我承认我刚刚说了他垃圾,但是不是所有情况下。有些时候人家还是蛮好用的,能保证并发情况下线程安全,毕竟人家用了Synchronized,你总不能说synchronized在任何情况下都垃圾吧。所以在一些低并发或写操作很多的情况下就用它吧。可能有些人说为什么是写操作,不是读操作?唉,一两句讲不清,你可以看看我其它的博文,说不定我以后写了一些并发博文,你也许就能找到答案。 ConcurrentHashMap,线程安全,前几个版本采用的是将整个hashtable分成若干个segment,分别对他们进行加锁操作,这就会使多线程在操作不同的segment时可以并发的处理,而不像HashTable那样将整体锁住,每次只能进行一次读或写,可以多个segment块同时进行。但是,在jdk 1.8做了一些优化,就是其中的table字段是用volatile进行修饰了(大家都知道volatile的作用,它提供的字段的可见性也就是保证每次读的内容都是从主内存中最新读出来的,但是不保证字段的原子性,也就是如果多个线程同时写,就会导致线程不安全),而且里面的hashentry不仅采用了Entry表而且还加上了红黑树,保证了当有较多冲突时的查找效率问题。这里不明白,别急,结合下面我将HashMap结构你在看这一段,就明白了。总之,使用ConcurrentHashMap你会在高并发中获得比较好的效果。     三,HashMap的实现原理(这个知道了,上面的那些“高端的”都是在这基础上添加了一些东西)     在这儿,我又想多讲两句了“equal()得到的两个对象如果相等,那他们的hashcode一定相等,但是hashCode()相等的两个对象,其equal()不一定相等”因为,hashmap肯定要用到equal(),hashCode()这两个是啥玩意?他们是java超级父类Object的两个函数,当然在Object里面equal()只是很简单地判断两个对象的地址是否相同。我们知道,HashMap中不允许有两个相同的键,可以有两个相同的值(这我又多扯了,别在意)里面判断键是否相同“最后一道”检测就是用equal(),既然说了“最后一道”那就有第一道,没错就是hashCode(),有什么作用呢?明明可以用equal()为什么还用hashCode()?答案是:当hashmap中的键值对多了后,你再往里面添加东西,如果是只用equal()你就不得不把将要放进hashmap的键值对的键和已经存在的键进行比较,这工作量可想而知,但是如果有了hashCode()后,我们是通过得到的值去找地址(你可以这么想),这不快多了!我们上面说了,hashcode相等的两个对象,其equal()不一定相等,那么当hashcode相同时也就是我们所说的出现hash冲突时会出现什么情况呢?这时有两种情况1,equal()也相等,那么显然,这个键值对不用进去了 2,equal()不等,那么这时就会在原有的基础上进行拉链(学过数据结构的童鞋肯定清楚啦,没学过也不急,等下给出hashmap的部分源码就知道了),然后使用链头插入,好了,下面给出起源,大家就可以自行脑补了static class Node<K,V> implements Map.Entry<K,V> {    final int hash;    //用来定位数组索引位置    final K key;    V value;    Node<K,V> next;   //链表的下一个node    Node(int hash, K key, V value, Node<K,V> next) { ... }    public final K getKey(){ ... }    public final V getValue() { ... }    public final String toString() { ... }    public final int hashCode() { ... }    public final V setValue(V newValue) { ... }    public final boolean equals(Object o) { ... }

}
这里面的next跟我们上面说的ConcurrentHashMap中的table字段作用差不多,都起着拉链的作用,好了,今天就到这了,码了三个小时,看个电影加个鸡腿犒劳一下自己~~~

阅读全文
0 0
原创粉丝点击