hashmap遍历方式(HashMap的底层原理)

admin 317 0

大家好,今天来为大家解答hashmap遍历方式这个问题的一些问题点,包括HashMap的底层原理也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~

一、在java中,遍历hashmap用什么方法

1、public static void main(String[] args){

2、Map<String,String> map=new HashMap<String,String>(){{//匿名内部类初始化

3、//遍历方法1:利用keyset进行遍历,它的优点在于可以根据你所想要的key值得到你想要的 values,更具灵活性!!

4、Set<String> keySet=map.keySet();

5、for(Iterator<String> it=keySet.iterator();it.hasNext();){

6、System.out.println(map.get(s));

7、//遍历方法2:最常规的一种遍历方法,最常规就是最常用的,虽然不复杂,但很重要,这是我们最熟悉的,就不多说了!!

8、Collection<String> c= map.values();

9、for(Iterator<String> it=c.iterator();it.hasNext();){

10、System.out.println(it.next());

11、//遍历方法3:比较复杂的一种遍历在这里,用map对象的keyEnter方法,呵呵~~他很暴力哦,它的灵活性太强了,想得到什么就能得到什么

12、Set<Map.Entry<String, String>> set=map.entrySet();

13、for(Iterator<Map.Entry<String, String>> it=set.iterator();it.hasNext();){

14、Map.Entry<String, String> mapEnter=it.next();

15、System.out.println("key="+mapEnter.getKey()+",value="+mapEnter.getValue());

二、HashMap是什么东西

1、HashMap,中文名哈希映射,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。HashMap数组每一个元素的初始值都是Null。

2、HashMap是基于哈希表的 Map接口的实现。此实现提供所有可选的映射操作,并允许使用 null值和 null键。(除了非同步和允许使用 null之外,HashMap类与 Hashtable大致相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

3、因为HashMap的长度是有限的,当插入的Entry越来越多时,再完美的Hash函数也难免会出现index冲突的情况。

4、HashMap数组的每一个元素不止是一个Entry对象,也是一个链表的头节点。每一个Entry对象通过Next指针指向它的下一个Entry节点。当新来的Entry映射到冲突的数组位置时,只需要插入到对应的链表即可。

三、如何遍历linkedhashmap

1、Iterator iter= map.entrySet().iterator();

2、Map.Entry entry=(Map.Entry) iter.next();

3、效率高,以后一定要使用此种方式!

4、Iterator iter= map.keySet().iterator();

5、HashMap的遍历有两种常用的方法,那就是使用keyset及entryset来进行遍历,但两者的遍历速度是有差别的,下面请看实例:

6、public static void main(String[] args){

7、HashMap hashmap= new HashMap();

8、long bs= Calendar.getInstance().getTimeInMillis();

9、Iterator iterator= hashmap.keySet().iterator();

10、System.out.print(hashmap.get(iterator.next()));

11、System.out.println(Calendar.getInstance().getTimeInMillis()- bs);

12、public static void listHashMap(){

13、java.util.HashMap hashmap= new java.util.HashMap();

14、long bs= Calendar.getInstance().getTimeInMillis();

15、java.util.Iterator it= hashmap.entrySet().iterator();

16、java.util.Map.Entry entry=(java.util.Map.Entry) it.next();

17、// entry.getKey()返回与此项对应的键

18、// entry.getValue()返回与此项对应的值

19、System.out.print(entry.getValue());

20、System.out.println(Calendar.getInstance().getTimeInMillis()- bs);

21、对于keySet其实是遍历了2次,一次是转为iterator,一次就从hashmap中取出key所对于的value。而entryset只是遍历了第一次,他把key和value都放到了entry中,所以就快了。

22、注:Hashtable的遍历方法和以上的差不多!

23、以下通过程序来简单实践一下HashMap的的遍历

24、如果要保持HashMap的遍历顺序和原插入顺序一致,可以使用LinkedHashMap,使用方法和HashMap一样,改一下声明即可:LinkedHashMap myMap= new LinkedHashMap();当然需要导入:java.util.LinkedHashMap

25、public static void main(String[] args){

26、// TODO Auto-generated method stub

27、System.out.println("--------------------遍历key和value----------------------");

28、for(Iterator iter= myMap.entrySet().iterator();iter.hasNext();){

29、Map.Entry element=(Map.Entry)iter.next();

30、Object strKey= element.getKey();

31、Object strObj= element.getValue();

32、System.out.println("myMap.get(\""+strKey+"\")="+strObj);

33、System.out.println("--------------------遍历整个HashMap----------------------");

34、Collection objs= myMap.entrySet();

35、for(Iterator iterator=objs.iterator(); iterator.hasNext();){

36、System.out.println("--------------------遍历HashMap的key----------------------");

37、Collection keys= myMap.keySet();

38、for(Iterator iterator=keys.iterator(); iterator.hasNext();){

39、System.out.println("--------------------遍历HashMap的value----------------------");

40、Collection values= myMap.values();

41、for(Iterator iterator=values.iterator(); iterator.hasNext();){

42、Object value= iterator.next();

43、--------------------遍历key和value----------------------

44、--------------------遍历整个HashMap----------------------

45、--------------------遍历HashMap的key----------------------

46、--------------------遍历HashMap的value----------------------

四、HashMap和List遍历方法总结及如何遍历删除

(一)List的遍历方法及如何实现遍历删除

我们造一个list出来,接下来用不同方法遍历删除,如下代码:

List<String> list= new ArrayList<String>();famous.add("zs");famous.add("ls");famous.add("ww");famous.add("dz");

for(int i=0;i<list.size();i++){if(list.get(i).equals("ls"))list.remove(i);}

这是一种很常见的遍历方式,但是使用这种遍历删除元素会出现问题,原因在于删除某个元素后,list的大小发生了变化,而你的索引

也在变化,所以会导致你在遍历的时候漏掉某些元素。比如当你删除第一个元素后,继续根据索引访问第二个元素后,因为删除的原因,

后面的元素都往前移动了以为,所以实际访问的是第三个元素。因此,这种遍历方式可以用在读取元素,而不适合删除元素。

for(String x:list){if(x.equals("ls"))list.remove(x);}

这也是一种很常见的遍历方式,但是使用这种遍历删除元素也会出现问题,运行时会报ConcurrentModificationException异常

其实增强for循环是java语法糖的一种体现,如果大家通过反编译得到字节码,那么上面这段代码的内部实现如下所示:

for(Iterator<String> it= list.iterator();it.hasNext();){String s= it.next();if(s.equals("madehua")){list.remove(s);}}

下面就解释为什么会报ConcurrentModificationException异常。分析Iterator的源代码,重点分析整个调用该过程中的

private class Itr implements Iterator<E>{ int cursor;// index of next element to return int lastRet=-1;// index of last element returned;-1 if no such int expectedModCount= modCount; public boolean hasNext(){ return cursor!= size;// size为集合中元素的个数} public E next(){ checkForComodification(); int i= cursor; if(i>= size) throw new NoSuchElementException(); Object[] elementData= ArrayList.this.elementData; if(i>= elementData.length) throw new ConcurrentModificationException(); cursor= i+ 1; return(E) elementData[lastRet= i];}/*此方法并没被调用,只是调用List.remove方法 public void remove(){ checkForComodification(); try{ ArrayList.this.remove(lastRet);// size字段减1 cursor= lastRet; lastRet=-1; expectedModCount= modCount;} catch(IndexOutOfBoundsException ex){ throw new ConcurrentModificationException();}}*/ final void checkForComodification(){//检查修改和当前版本号是否一致,不一致则抛出异常 if(modCount!= expectedModCount) throw new ConcurrentModificationException();}}// List.remove@Override public boolean remove(Object object){ Object[] a= array; int s= size; if(object!= null){ for(int i= 0; i< s; i++){ if(object.equals(a[i])){ System.arraycopy(a, i+ 1, a, i,--s- i); a[s]= null;// Prevent memory leak size= s; modCount++;//核心代码:修改了版本号。这样当checkForComodification的时候,modCount值就和expectedModCount不同 return true;}}} else{ for(int i= 0; i< s; i++){ if(a[i]== null){ System.arraycopy(a, i+ 1, a, i,--s- i); a[s]= null;// Prevent memory leak size= s; modCount++; return true;}}} return false;}

接下来梳理一下流程,这时候你就会发现这个异常是在next方法的checkForComodification中抛出的。抛出的原因是

modCount!=expectedModCount。这里的modCount是指这个list对象从呢我出来到现在被修改的次数,当调用list

的add或者remove方法的时候,这个modCount都会自动增减;iterator创建的时候modCount被复制给了

expectedModcount,但是调用list的add和remove方法的时候不会同时自动增减expectedModcount,这样就导致

两个count不相等,从而抛出异常。大家如果理解了上面的执行流程,以后碰到类似这种问题,比如如果删除的是倒数

第二个元素却不会碰到异常。就会知道为什么了。

Iterator<String> it= list.iterator();while(it.hasNext()){String x= it.next();if(x.equals("del")){it.remove();}}

这种方式是可以正常遍历和删除的。但是你可能看到上面代码感觉和增强for循环内部实现的代码差不多,其实差别就在于上面使用

一个使用list.remove(),一个使用it.remove()。

(二)HashMap的遍历删除及如何实现遍历删除

一样我们先造一个hashmap出来,如下:

private static HashMap<Integer, String> map= new HashMap<Integer, String>();; public static void main(String[] args){ for(int i= 0; i< 10; i++){ map.put(i,"value"+ i);}}

for(Map.Entry<Integer, String> entry: map.entrySet()){Integer key= entry.getKey();if(key% 2== 0){System.out.println("To delete key"+ key);map.remove(key);System.out.println("The key"++ key+" was deleted");}

这种遍历删除依旧会报ConcurrentModificationException异常,

Set<Integer> keySet= map.keySet(); for(Integer key: keySet){ if(key% 2== 0){ System.out.println("To delete key"+ key); keySet.remove(key); System.out.println("The key"++ key+" was deleted");}}

这种遍历删除依旧会报ConcurrentModificationException异常,

Iterator<Map.Entry<Integer, String>> it= map.entrySet().iterator();while(it.hasNext()){Map.Entry<Integer, String> entry= it.next();Integer key= entry.getKey();if(key% 2== 0){ System.out.println("To delete key"+ key); it.remove(); System.out.println("The key"++ key+" was deleted");}}

分析上述原因,如果大家理解了List的遍历删除,那么感觉HashMap的遍历删除是不是有类似之处啊。下面就分析一下原因:

如果查询源代码以上的三种的删除方式都是通过调用HashMap.removeEntryForKey方法来实现删除key的操作。

在removeEntryForKey方法内知识一场了key modCount就会执行一次自增操作,此时modCount就与expectedModCOunt不一致了

,上面三种remove实现中,只有第三种iterator的remove方法在调用完removeEntryForKey方法后同步了expectedModCount值与

modCount相同,所以iterator方式不会抛出异常。最后希望大家遇到问题到查询源代码,它会给你最好的解释!

好了,本文到此结束,如果可以帮助到大家,还望关注本站哦!