当前位置: 首页 > 后端技术 > Java

探究Java中HashMap的keySet()方法

时间:2023-04-01 20:56:32 Java

PS:本文为转载文章,原文可读性会更好。文末有原文链接。ps:本文基于JDK1.8。解释。在我们平时的软件开发中,使用Java语言编写程序的读者都知道,我们有时会用到HashMap,尤其是HashMap的keySet()方法。让我们从一段代码开始;Mapmap=newHashMap();for(inti=1;i<30;i++){map.put("key"+i,i);}//1,for(HashMap.Entryentry:map.entrySet()){Stringkey=entry.getKey();intvalue=entry.getValue();System.out.println("key="+key+",value="+value);}我们平时使用的增强型for循环,经常会用到,因为遍历的目标是数组或者集合;好吧,我们先说增强for循环map.entrySet()的情况,我们先从增强for循环说起遍历数组的代码如图1所示:图片图1当图1中的代码块实际上是为了被执行时,实际上会变成图2中待执行的代码块Figure2见图2,当我们用增强的for循环遍历数组时,最终会变成:从索引处输出下标为0的元素,下标变量(var4)小于数组长度(var3)为条件,将下标变量的值加1,然后用下标将数组元素一一输出。现在我们回过头来看看注1中遍历的map.entrySet()是什么?我们打开HashMap的entrySet方法看一下;图中的entrySet方法返回一个Set集合;看这个三阶运算符,entrySet变量赋值给es变量,不管es是否为空,其实entrySet方法返回的是Set>对象肯定不为空;然后entrySet方法最终返回的是EntrySet对象,对吧,因为entrySet变量最终也指向了EntrySet对象;好了,我们点开注释2中的EntrySet类,看看它的具体实现;看到图中的EntrySet类,它有一个iterator方法,它返回迭代器对象Iterator>,我们看一下注释4中这个迭代器的具体实现类EntryIterator;看,EntryIterator继承了HashIterator,在next方法中,也调用了父类HashIterator中实现的nextNode方法;抽象类HashIterator{Node下一个;//下一个要返回的条目Nodecurrent;//当前条目intexpectedModCount;//用于快速失败的int索引;//当前插槽HashIterator(){expectedModCount=modCount;节点[]t=表;当前=下一个=空;索引=0;if(t!=null&&size>0){//前进到第一个条目do{//5,}while(indexnextNode(){Node[]t;//6、Nodee=next;如果(modCount!=expectedModCount)抛出新的ConcurrentModificationException();if(e==null)抛出新的NoSuchElementException();//7,if((next=(current=e).next)==null&&(t=table)!=null){do{//8,}while(index类型的数组,t中某个位置的元素可能存储了一个null值,可能只存储一个节点,也可能存储链表的头节点,它可以保存红黑树的根节点;为了便于理解,我先画出数组t中存储的元素的结构图,假设t中存储的元素如图4所示;图中假设hashIterator的nextNode方法中next变量遍历的t数组如图4所示;遍历迭代器的时候,一定要执行迭代器的next和hasNext方法吧?好吧,我们看,第一次执行nextNode方法时,只返回t[1]中的元素,然后判断t[1]中元素的下一个节点是否为空(见注释7中的代码),如果为空,则执行注8中的dowhile语句,检查t数组当前索引(当前索引为1)的下一个索引存储的元素是否为空,如果不为空,则使用next变量指向下一个索引存放的元素,然后返回当前索引(当前索引为1)的元素;注释7中的代码是遍历链表或红黑树,取出链表或红黑树的下一个元素,注释8中的代码是遍历t数组的索引,取出保存在t'数组的下一个索引中的元素。好了,我们回过头来看看上面的for循环map.entrySet()增强的案例。map.entrySet()得到一个EntryIterator的迭代器,然后结合EntryIterator迭代器的next和HasNext方法得到Hash-Map.Entry对象,通过HashMap.Entry<得到key和valueString-g,Integer>object,看看是不是这样,我们通过开发工具(AndroidStudio)编译一下,看看它的字节码文件;图中我代码的包名是com.xe.customfactory,哈哈,看到了吗,真的map.entrySet()得到了一个EntryIterator迭代器,然后通过EntryIterator迭代器的next和HasNext方法配合使用。