简单分析Java的HashMap.entrySet()的实现

关于Java的HashMap.entrySet(),文档是这样描述的:这个方法返回一个Set,这个Set是HashMap的视图,对Map的操作会在Set上反映出来,反过来也是。原文是

Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.

本文通过源码简单分析这一功能的实现。

首先要简单介绍一下HashMap的内部存储。我们知道,Map是用来存储key-value类型数据的,一个<k, v>对在Map的接口定义中被定义为Entry,HashMap内部实现了Entry接口。HashMap内部维护一个Entry数组。

transient Entry[] table;

当put一个新元素的时候,根据key的hash值计算出对应的数组下标。数组的每个元素是一个链表的头指针,用来存储具有相同下标的Entry。

Entry[] table
    +---+
    | 0 | -> entry_0_0 -> entry_0_1 -> null
    +---+
    | 1 | -> null
    +---+
    |   |

     ...

    |n-1| -> entry_n-1_0 -> null
    +---+

entrySet()方法返回的是一个特殊的Set,定义为HashMap的内部私有类

private final class EntrySet extends AbstractSet<Map.Entry<K,V>>

主要看一下这个Set的iterator()方法。这个方法很简单,返回一个EntryIterator类型的实例。EntryIterator类型是泛型HashIterator<T>的一个子类,这个类的内容很简单,唯一的代码是在next()函数中调用了HashIteratornextEntry()方法。所以,重点就变成了分析nextEntry()方法。

HashIterator通过遍历table数组,实现对HashMap的遍历。内部维护几个变量:index记录当前在table数组中的下标,current用来记录当前在table[index]这个链表中的位置,next指向current的下一个元素。nextEntry()的完整代码如下:

final Entry<K,V> nextEntry() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    Entry<K,V> e = next;
    if (e == null)
        throw new NoSuchElementException();

    if ((next = e.next) == null) {
        Entry[] t = table;
        while (index < t.length && (next = t[index++]) == null)
            ;
    }
    current = e;
    return e;
}

第一个if用来判断在多线程的情况下是否出现并发错误,这里暂时不讨论。如果next不是null,那么返回并更新next。更新方法是第三个if的内容:如果当前链表还没有结束,则简单的把next向后移一个;否则在table中查找下一个非空的slot。

总结一下,HashMap的entrySet()方法返回一个特殊的Set,这个Set使用EntryIterator遍历,而这个Iterator则直接操作于HashMap的内部存储结构table上。通过这种方式实现了“视图”的功能。整个过程不需要任何辅助存储空间。

p.s. 从这一点也可以看出为什么entrySet()是遍历HashMap最高效的方法,原因很简单,因为这种方式和HashMap内部的存储方式是一致的。

简单分析Java的HashMap.entrySet()的实现

时间: 2024-07-29 20:55:25

简单分析Java的HashMap.entrySet()的实现的相关文章

简单说说Java知识点 -- HashMap

一)HashMap基本简述 HashMap底层主要是基于数组和链表实现的,数组中存放的元素就是一个单向链表,因此我们可以将HashMap理解为单向链表数组. 在HashMap源码中我们可以看到其中一些关键属性,例如:transient Entry[] table; 这个就是用来存储元素的实体数组,其中数组的类型为Entry,这与我们上面对HashMap定义是一致的.  1 transient Entry[] table; 二)HashMap的get操作 HashMap进行数据存储时会通过key的

java基础----&gt;hashMap的简单分析(一)

HashMap是一种十分常用的数据结构对象,可以保存键值对.它在项目中用的比较多,今天我们就来学习一下关于它的知识. HashMap的简单使用 一.hashMap的put和get方法 Map<String, String> map = new HashMap<>(); map.put("username", "huhx"); map.put("password", "1234"); map.put(nu

java基础----&gt;hashSet的简单分析(一)

对于HashSet而言,它是基于HashMap实现的,底层采用HashMap来保存元素的.今天我们就简单的分析一下它的实现. HashSet的简单分析 一.hashSet的成员变量组成 public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable private transient HashMap<E,Object> map;

《Java源码分析》:HashMap

<Java源码分析>:HashMap 看过很多次HashMap的源码了,但是,每次都没有做记录,因此,每次记忆都不太深,今天在看别人博客时提到Hashtable是线程安全的,Hashtable中的方法都用了synchronized进行了同步,于是就看了下Hashtable的源码,在看的过程中,写了篇博客,现在2016年7月20日22:03:53,还在教研室,感觉回寝室还早,因此,决定再看下HashMap的源码,也随便以写博客的形式做点笔记. 还是很看其他类的源码一样,先看构造函数,然后看一些比

Java之OutOfMemoryError简单分析

Java之OutOfMemoryError简单分析 最近编码遇到了Java内存溢出的问题,所以就想顺便总结一下几种导致Java内存溢出的栗子,以及碰到Java内存溢出要如何去解决. Java堆溢出 Java堆用于存储对象实例,只要不断的创建对象,并且保证GC Roots到对象之间有可达的路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆容量限制之后就会产生内存溢出的异常. 下面通过一段代码进行堆内存溢出异常的测试. 1 public class HeapOOM{ 2 static cl

Java动态替换InetAddress中DNS的做法简单分析1

在java.net包描述中, 简要说明了一些关键的接口. 其中负责networking identifiers的是Addresses. 这个类的具体实现类是InetAddress, 底层封装了Inet4Address与Inet6Address的异同, 可以看成一个Facade工具类. A Low Level API, which deals with the following abstractions: Addresses, which are networking identifiers,

java 中 “文件” 和 “流” 的简单分析

java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 //创建一个File 对象,检验文件是否存在,若不存在就创建然后对File package wfu; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.Scanner; pu

JAVA API HashMap 分析

AbstractMap: 数据结构: Entry<K,V> 是 Map接口内部的一个接口,在具体的实现类中会被实现成不同静态内部类,他们有不同的的键值对结构.Set<K> keySet();Collection<V> values(); transient volatile Set<K> keySet = null;transient volatile AbstractCollection<V> values = null;keySet,valu

Java面试&amp; HashMap实现原理分析

1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端.  数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O(1):数组的特点是:寻址容易,插入和删除困难: 链表 链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N).链表的特点是:寻址困难,插入和删除容易. 哈希表 那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表