文章标题 【Java源码浅析】关于HashMap和HashSet的异同和源码分析

最近学了JAVA之后,对JAVA源码实现很感兴趣,于是就在自己的Eclipse里看JAVA里的一些常用的类的源码实现,自己水平也不是很高,有不懂的代码还是要去看别人写的博客,我写的这篇文章也是看了别人的博客后,加上自己看了源码后的理解而作,既是希望自己能从此掌握这两个类的实现,也能帮助那些渴望成为编程大牛的孩子。大家有不理解的可以看这篇文章 https://www.baidu.com/link?url=IqZUK4wSjRAZ-yDH2wgp_x3uosAcN1bFUv7GYaQk4DStjeU559QtWuUsHAu9WViOKJXaaW3qJnBJv3KH9jRI2nhOdw-zjOi-GA4OspLHYUK&wd=&eqid=cf09827d00034226000000035991cae8
HashMap和HashSet是java里很常用的两个类,他们有
相同之处
1:都是用Hash算法来存储元素的值
2:查找存取的性能都很好(当然比数组还是稍微差一些)
3:存储的值都允许为null
4:都不是线程安全的
5:都不维护元素的顺序,也就是说,是乱序存放的
6:都是collection框架的一部分
不同之处
1:HashSet里的value不允许重复,但是HashMap的value是允许重复的
2:HashMap是以键值对来存储的,而HashSet仅仅是存放值
3:HashMap实现的是Map接口,HashSet实现的是Set接口
4:HashMap使用键对象来计算Hashcode,HashSet使用值对象来计算hashcode(因为它只存放值,所以只能用值来计算hashcode)

下面就是具体的分析源码了,先把源码贴上,我们边看源码边分析。先分析HashMap(hashmap的实现原理图接我建议先看这篇博文,我觉得讲的很清楚 http://blog.csdn.net/eson_15/article/details/51158865?locationNum=2&fps=1

/*HashMap 继承的是AbstractMap,它实现了Map, Cloneable, Serializable 三个类*/
public class HashMap extends AbstractMap
    implements Map, Cloneable, Serializable
{
   /*DEFAULT_INITIAL_CAPACITY = 16 默认容量为16*/
    static final int DEFAULT_INITIAL_CAPACITY = 16;
    static final int MAXIMUM_CAPACITY = 1073741824;

    /*默认的负载因子的值*/
    static final float DEFAULT_LOAD_FACTOR = 0.75F;

    /*说一下  transient 。transient是Java语言的关键字,用来表示一个域不象串行化的一部分。当持久化对象时,可能有一个特殊的对象数据成员,我们不想serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。然而非transient型的变量是被包括进去的。*/
    transient Entry[] table;/* table 是Entry[]数组变量,也就是键值对类型的数组,一个可以对应一个value*/
    transient int size;
    int threshold; /* 极限容量*/
    final float loadFactor; /*负载因子*/
    transient volatile int modCount; /*用来记录对map的操作次数,这个变量特别重要*/
    private transient Set entrySet = null;
    private static final long serialVersionUID = 362498820763181265L;

    /*静态的Entry类,实现Map.Entry,里面就定义了,key,value,next,hash我们需要用的变量,key,value不说了,next变量相当于一个指针,在用 Iterator 遍历时会发挥很大的作用*/
    static class Entry implements Map.Entry
    {
    final Object key;
    Object value;
    Entry next;
    final int hash;
    /*Entry 的构造函数*/
    Entry(int i, Object object, Object object_0_, Entry entry_1_) {
        value = object_0_;
        next = entry_1_;
        key = object;
        hash = i;
    }
     /*得到map里存储的key值*/
    public final Object getKey() {
        return key;
    }
    /*得到value值*/
    public final Object getValue() {
        return value;
    }
    /*设置value值*/
    public final Object setValue(Object object) {
        Object object_2_ = value; /*用一个变量来保存旧的值*/
        value = object; /*设置新的值*/
        return object_2_; /*返回旧值*/
    }
    /*判断两个对象是否相等的方法*/
    public final boolean equals(Object object) {
        if (!(object instanceof Map.Entry))
        return false;   /*首先判断类型是否相等,不相等直接返回false*/
        /*强制转换object为Entry对象类型,用entry_3_ 变量表示*/
        Map.Entry entry_3_ = (Map.Entry) object;
        Object object_4_ = getKey(); /*用getKey方法得到key值(这是用equals方法的那个对象的key值,而不是object的key值)*/

        /*这才是object的key值,entry_3_ 表示的就是object*/
        Object object_5_ = entry_3_.getKey();
        /*判断key值是否相等(object_4_ == object_5_), (object_4_ != null && object_4_.equals(object_5_))key值不能为null且要相等,否则就没必要比较value值了*/
        if (object_4_ == object_5_
        || object_4_ != null && object_4_.equals(object_5_)) {
        /*就可以比较value值是否相等,逻辑与比较key值相同*/
        Object object_6_ = getValue();
        Object object_7_ = entry_3_.getValue();
        if (object_6_ == object_7_
            || object_6_ != null && object_6_.equals(object_7_))
            return true;
        }
        return false;
    }
    /*根据key值和value值来计算hash值,来定位此对象在hashmap中的位置*/
    public final int hashCode() {
        return ((key == null ? 0 : key.hashCode())
            ^ (value == null ? 0 : value.hashCode()));
    }
    /*toString() 方法,没什么好说的*/
    public final String toString() {
        return new StringBuilder().append(getKey()).append("=").append
               (getValue()).toString();
    }

    void recordAccess(HashMap hashmap) {
        /* empty */
    }

    void recordRemoval(HashMap hashmap) {
        /* empty */
    }
    }
    /*内部类,定义EntryIterator 迭代器和一些其他方法,是可以被hashmap类直接访问的,从名字可以知道,它是用来迭代Entry类型对象的迭代器*/
    private final class EntryIterator extends HashIterator
    {
    final HashMap this$0 = HashMap.this; (HashMap.this表示引用的是HashMap这个类的实例,不这样声明编译器会不知道引用的是哪个实例)

    /*直接继承父类的EntryIterator()*/
    private EntryIterator() {
        super();
    }
     /*next()方法,迭代器时会使用,是实现迭代器的重要方法*/
    public Map.Entry next() {
        return nextEntry();
    }

    public volatile Object next() {
        return next();
    }

    EntryIterator(ANONYMOUS CLASS java.util.HashMap$1 var_1) {
        this();
    }
    }
    /*EntrySet类,将Entry对象封装成一个Set,这样可以用来作遍历hashmap集合,速度很快*/
    private final class EntrySet extends AbstractSet
    {
    final HashMap this$0 = HashMap.this;
    /*使用父类的构造函数*/
    private EntrySet() {
        super();
    }
    /*EntrySet的迭代器*/
    public Iterator iterator() {
        return this$0.newEntryIterator();
    }
    /*判断是否包含此object对象*/
    public boolean contains(Object object) {
        if (!(object instanceof Map.Entry))
        return false;   /*同样是先判断类型是否相等*/
        Map.Entry entry = (Map.Entry) object;
        /*通过getEntry()方法通过entry.getKey()得到Entry对象*/
        Entry entry_8_ = this$0.getEntry(entry.getKey());
        /*调用之前的equals方法来判断是否相等,相等则返回true*/
        return entry_8_ != null && entry_8_.equals(entry);
    }
     /*调用hashmap.removeMapping(object)方法,如果成功删除,则放回true,否则object不在keyset里,则放回false*/
    public boolean remove(Object object) {
        return this$0.removeMapping(object) != null;
    }
   /*整个map的大小*/
    public int size() {
        return this$0.size;
    }
    /*调用hashmap的clear()方法,这个方法在下面会说到*/
    public void clear() {
        this$0.clear();
    }

    EntrySet(ANONYMOUS CLASS java.util.HashMap$1 var_1) {
        this();
    }
    }
    /*真正到了重要的地方,这个类特别重要,也是个迭代类,是内部抽象类,这个类的方法常常拿来做hashmap的迭代*/
    private abstract class HashIterator implements Iterator
    {
    Entry next; /*entry类型的变量,是用来保存下一个迭代对象的  指针  */
    int expectedModCount; /* 这个int 型变量是跟前面 modCount 对应的,他们一定要相等,不然就会报错,他们是用来记录对map集合的操作次数,即增删改的次数*/
    int index; /*hash 下标,标识map中元素的位置*/
    Entry current; /*迭代过程中当前的迭代对象*/
    final HashMap this$0 = HashMap.this; /* 要记得它还是当前这个hashmap的引用实例*/

    /*构造函数 注意 expectedModCount = modCount; 是要相等的 */
    HashIterator() {
        super();
        expectedModCount = modCount;
        if (size > 0) {
        Entry[] entrys = table; 
        while (index < entrys.length
               && (next = entrys[index++]) == null) {
            /* empty */  /*为什么里面是空的,我也不是太清楚,我看别人博客说的是,这是为了让你自己写你需要的实现,while里的条件也不难理解*/
        }
        }
    }
    /* hasNext 方法,是不是很简单?只要还有next指针,就可以继续遍历,否则返回false*/
    public final boolean hasNext() {
        return next != null;
    }

    /*这个类返回Entry类型的对象 */
    final Entry nextEntry() {
    / * 先判断modCount == expectedModCount 是否相等,如果不等,就会抛出异常 ConcurrentModificationException()*/ 

        if (this$0.modCount != expectedModCount)
        throw new ConcurrentModificationException();

        /*将next对象赋给 entry变量*/
        Entry entry = next;
       /*判断是否为null,为null表示没有这个元素存在map里*/
        if (entry == null)
        throw new NoSuchElementException();
        /*以上的判断都通过了,就可以真正进行nextEntry 的判断了,(next = entry.next) == null 因为 hashmap里存放数据是不连续的,如果下一个指针所指的entry对象为null,就通过下面的代码来找到下一个不为null的对象,当entry.next为空时,就要循环找到下一个不为空的entry对象,entry.next不为null,则会跳过这段代码*/
        if ((next = entry.next) == null) {
        Entry[] entrys = this$0.table;
        /*while 的作用,当遇到不为null的entry对象就跳出循环,并且赋给了 next 指针 要是一直是null,那么next指针也是null,index标识当前entry对象在进入循环时的位置,并且会执行index++操作*/
        while (index < entrys.length
               && (next = entrys[index++]) == null) {
            /* empty */
        }
        }
        /*当前迭代的对象是entry*/
        current = entry;
        return entry; /*返回entry*/
    }
    /* 删除操作*/
    public void remove() {
    /*当前要删除的对象不能为null*/
        if (current == null)
        throw new IllegalStateException();
        /*modCount ,expectedModCount 一定要相等*/
        if (this$0.modCount != expectedModCount)
        throw new ConcurrentModificationException();
        /*先得到key*/
        Object object = current.key;
        /*将它设为null,这样GC就会回收它*/
        current = null;
        /*调用此方法,就能以key来删除 entry对象*/
        this$0.removeEntryForKey(object);
        /*删除操作后要再次令 expectedModCount = this$0.modCount*/
        expectedModCount = this$0.modCount;
    }
    }
    /*这是以key来作迭代的 内部类,继承 HashIterator 原理都差不多*/
    private final class KeyIterator extends HashIterator
    {
    final HashMap this$0 = HashMap.this;

    private KeyIterator() {
        super();
    }
    /*得到下一个key*/
    public Object next() {
        return nextEntry().getKey();
    }

    KeyIterator(ANONYMOUS CLASS java.util.HashMap$1 var_1) {
        this();
    }
    }
    /* keyset 也就是所有的key的集合,也可以拿来遍历map的key的集合*/
    private final class KeySet extends AbstractSet
    {
    final HashMap this$0 = HashMap.this;

    private KeySet() {
        super();
    }

    public Iterator iterator() {
        return this$0.newKeyIterator();
    }

    public int size() {
        return this$0.size;
    }
    /*调用containsKey(object) 来判断是否包含,containsKey(object) 在后面会说*/
    public boolean contains(Object object) {
        return this$0.containsKey(object);
    }
    /*同上的remove方法的逻辑*/
    public boolean remove(Object object) {
        return this$0.removeEntryForKey(object) != null;
    }

    public void clear() {
        this$0.clear();
    }

    KeySet(ANONYMOUS CLASS java.util.HashMap$1 var_1) {
        this();
    }
    }
    /*同keyIterator 的实现原理和思路*/
    private final class ValueIterator extends HashIterator
    {
    final HashMap this$0 = HashMap.this;

    private ValueIterator() {
        super();
    }

    public Object next() {
        return nextEntry().value;
    }

    ValueIterator(ANONYMOUS CLASS java.util.HashMap$1 var_1) {
        this();
    }
    }

    private final class Values extends AbstractCollection
    {
    final HashMap this$0 = HashMap.this;

    private Values() {
        super();
    }

    public Iterator iterator() {
        return this$0.newValueIterator();
    }

    public int size() {
        return this$0.size;
    }

    public boolean contains(Object object) {
        return this$0.containsValue(object);
    }

    public void clear() {
        this$0.clear();
    }

    Values(ANONYMOUS CLASS java.util.HashMap$1 var_1) {
        this();
    }
    }

    /*终于找到hashmap的构造方法了。i 是设置 entry[] 数组的大小, i不能小于0,也不能大于1073741824,f是负载因子的大小*/
    public HashMap(int i, float f) {
    if (i < 0)
        throw new IllegalArgumentException
              (new StringBuilder().append
               ("Illegal initial capacity: ").append
               (i).toString());
    if (i > 1073741824)
        i = 1073741824;
    if (f <= 0.0F || Float.isNaN(f))
        throw new IllegalArgumentException(new StringBuilder().append
                           ("Illegal load factor: ")
                           .append
                           (f).toString());
    int i_9_;
    for (i_9_ = 1; i_9_ < i; i_9_ <<= 1) {
        /* empty */
    }
    loadFactor = f;
    threshold = (int) ((float) i_9_ * f);
    table = new Entry[i_9_];
    /*初始化的方法,是空的*/
    init();
    }
    /*这个大家都能看懂吧*/
    public HashMap(int i) {
    this(i, 0.75F);
    }
    /*默认的构造方法,如果不加参数,就默认这么设置*/
    public HashMap() {
    loadFactor = 0.75F;
    threshold = 12;
    table = new Entry[16];
    init();
    }
    /*这个构造方法比较复杂,好像也不常用*/
    public HashMap(Map map) {
    this(Math.max((int) ((float) map.size() / 0.75F) + 1, 16), 0.75F);
    /*注意这个方法,后面会说到*/
    putAllForCreate(map);
    }

    void init() {
    /* empty */
    }
    /*这就是计算hash值的方法,想深入研究的可以去查查实现原理,我不是太懂*/
    static int hash(int i) {
    i ^= i >>> 20 ^ i >>> 12;
    return i ^ i >>> 7 ^ i >>> 4;
    }
    /*这个方法计算出该entry对象在table数组里存放的位置, i_10_ 变量将要存的是table数组的长度,传入table数组的长度就不会使计算出的位置超越数组的长度*/
    static int indexFor(int i, int i_10_) {
    return i & i_10_ - 1;
    }

    public int size() {
    return size;
    }
    /*这个方法也是很简单的,size大于0,就不是空的*/
    public boolean isEmpty() {
    return size == 0;
    }
    /*get方法会根据object(实际上它是key的值)得到所存贮的值*/
    public Object get(Object object) {
    if (object == null)  /*为null时,用getForNullKey() 方法得到它的值*/
        return getForNullKey();
    int i = hash(object.hashCode()); /*得到hash值,即索引*/
    /*用for循环来循环此table[indexFor(i, table.length)]处是否存在链表,有链表则遍历找出要找的key和它的值*/
    for (Entry entry = table[indexFor(i, table.length)]; entry != null;
         entry = entry.next) {
        Object object_11_;
        /*if条件里是要对比key值和计算出的hash值的,最后还得用equals方法进行比较,才能真正返回value值*/
        if (entry.hash == i && ((object_11_ = entry.key) == object
                    || object.equals(object_11_)))
        return entry.value;
    }
    return null;
    }
    /*当key为空时,调用此方法得到对应value*/
        private Object getForNullKey() {
        /*为什么从0开始遍历呢?因为hashmap里默认将key=null的key-value对放在table[0]处,for循环用来检查是否有链表存在,有则遍历得到第一个key为null的值*/
    for (Entry entry = table[0]; entry != null; entry = entry.next)    {
        if (entry.key == null)
        return entry.value;
    }
    return null;
    }
    /*通过key值来判断此key是否包含在table数组里*/
    public boolean containsKey(Object object) {
    return getEntry(object) != null;
    }
    /*getEntry方法,很重要,在很多方法里都调用了它*/
    final Entry getEntry(Object object) {
    /*首先还是先计算它的hash值,它是用来在indexFor(i, table.length)方法里定位此key在table数组里的地址的*/
    int i = object == null ? 0 : hash(object.hashCode());
    /*此for循环的作用和之前的一样,大家很容易看懂的*/
    for (Entry entry = table[indexFor(i, table.length)]; entry != null;
         entry = entry.next) {
        Object object_12_;
        if (entry.hash == i
        && ((object_12_ = entry.key) == object
            || object != null && object.equals(object_12_)))
        return entry;
    }
    return null;
    }
    /*hashmap里的put方法,大家经常用,现在看看是怎么实现的*/
    public Object put(Object object, Object object_13_) {
    /*先判断key是否为空,为空则用另外的方法来put它,即putForNullKey(object_13_) 方法*/
    if (object == null)
        return putForNullKey(object_13_);
        /*一样得到hash值*/
    int i = hash(object.hashCode());
    int i_14_ = indexFor(i, table.length); /*定位在table数组的位置*/
    /*判断此位置是否有链表,此段代码会判断是否已经有相同的key值存在,如果已经有了,会覆盖value值,没有则会在此位置插入一个entry对象*/
    for (Entry entry = table[i_14_]; entry != null; entry = entry.next) {
        Object object_15_;
        if (entry.hash == i && ((object_15_ = entry.key) == object
                    || object.equals(object_15_))) {
        Object object_16_ = entry.value;
        entry.value = object_13_; /*替换value值*/
        entry.recordAccess(this);
        return object_16_; /*会返回旧值*/
        }
    }
    /*如果没有已经存在的key值,会直接执行下面的代码*/
    modCount++; /*操作标识数+1*/
    addEntry(i, object, object_13_, i_14_); /*新加了一个entry对象*/
    return null;
    }

    /*当key值为空时,object代表的要插入的value值*/
    private Object putForNullKey(Object object) {
    for (Entry entry = table[0]; entry != null; entry = entry.next) {       /*也替换key为null的entry对象的value值*/
        if (entry.key == null) {
        Object object_17_ = entry.value;
        entry.value = object;
        entry.recordAccess(this);
        return object_17_;
        }
    }
    /*前面的代码执行后没有找到null的key,则新插入一个新entry对象*/
    modCount++;
    addEntry(0, null, object, 0);
    return null;
    }
    /*这个方法实现原理和前面的方法相同*/
    private void putForCreate(Object object, Object object_18_) {
    int i = object == null ? 0 : hash(object.hashCode());
    int i_19_ = indexFor(i, table.length);
    for (Entry entry = table[i_19_]; entry != null; entry = entry.next) {
        Object object_20_;
        if (entry.hash == i
        && ((object_20_ = entry.key) == object
            || object != null && object.equals(object_20_))) {
        entry.value = object_18_;
        return;
        }
    }
    createEntry(i, object, object_18_, i_19_);
    }
    /*和上面的putAllForCreate方法是同一个方法,只是传入的是map*/
    private void putAllForCreate(Map map) {
    /*用iterator迭代器来迭代entrySet()集合里的entry对象*/
    Iterator iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry entry = (Map.Entry) iterator.next();
        putForCreate(entry.getKey(), entry.getValue());
    }
    }
    /*重置table数组的大小*/
    void resize(int i) {
    Entry[] entrys = table;
    int i_21_ = entrys.length;
    if (i_21_ == 1073741824)
        threshold = 2147483647; /*threshold=i_21*2-1 ,即如果table数组的大小已经达到1073741824了,就扩容*/
    else {
    / *不然,就按传入的i来重新创建Entry[]数组*/
        Entry[] entrys_22_ = new Entry[i];
        transfer(entrys_22_); /*此方法是重新复制table数组*/
        table = entrys_22_; /*将entrys_22_新数组的引用地址赋给table数组*/
        threshold = (int) ((float) i * loadFactor);
    }
    }
    /*这就是上面的transfer方法的实现*/
    void transfer(Entry[] entrys) {
    Entry[] entrys_23_ = table; /*这是没复制前的table*/
    int i = entrys.length;
    /*for循环遍历table,并将table里的entry对象存入entrys数组里*/
    for (int i_24_ = 0; i_24_ < entrys_23_.length; i_24_++) {
        Entry entry = entrys_23_[i_24_];
        if (entry != null) {
        entrys_23_[i_24_] = null; /*将它变成null*/
        do {
            Entry entry_25_ = entry.next;
            int i_26_ = indexFor(entry.hash, i); /*定位在entrys数组里的位置*/
            entry.next = entrys[i_26_];
            entrys[i_26_] = entry; /*复制操作,将entry赋给entrys[i_26_]*/
            entry = entry_25_; /*将原来的entry.next赋给entry,用来作while循环*/
        } while (entry != null);
        }
    }
    }
    /*将map里的对象全放进hashmap里*/
    public void putAll(Map map) {
    int i = map.size(); /*判断map的对象的多少*/
    /*对i的值进行判断,这是有必要的*/
    if (i != 0) {
        if (i > threshold) {
        int i_27_ = (int) ((float) i / loadFactor + 1.0F);
        if (i_27_ > 1073741824)
            i_27_ = 1073741824;
        int i_28_;
        for (i_28_ = table.length; i_28_ < i_27_; i_28_ <<= 1) {
            /* empty */
        }
        if (i_28_ > table.length)
            resize(i_28_);
        }
        /*用迭代器来迭代put每一个元素进hashmap*/
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
        Map.Entry entry = (Map.Entry) iterator.next();
        put(entry.getKey(), entry.getValue());
        }
    }
    }
    /*删除操作*/
    public Object remove(Object object) {
    Entry entry = removeEntryForKey(object);
    return entry == null ? null : entry.value;
    }
    /*删除操作具体实现*/
    final Entry removeEntryForKey(Object object) {
    /*得到hash值*/
    int i = object == null ? 0 : hash(object.hashCode());
    int i_29_ = indexFor(i, table.length); /*table
    数组里object key值对应的地址*/
    Entry entry = table[i_29_]; /*得到key对应的那个对象*/
    Entry entry_30_;
    Entry entry_31_;
    /*还是在遍历当前位置是否有链表存在,有的话就遍历判断*/
    for (entry_31_ = entry; entry_31_ != null; entry_31_ = entry_30_) {
        entry_30_ = entry_31_.next; /*entry_30_存链表上当前entry对象的下一个对象的指针*/
        Object object_32_;
        if (entry_31_.hash == i
        && ((object_32_ = entry_31_.key) == object
            || object != null && object.equals(object_32_))) {
        modCount++; /*删除操作后要modCount++*/
        size--; /*大小要减一*/
        if (entry == entry_31_) /*如果要删除的是当前的第一个entry对象*/
            table[i_29_] = entry_30_; /*则将entry_31_.next存在table[i_29_]中,即将原来是在链表头的entry对象的下一个对象移到表头来,因为当前在表头的entry对象要被删除了*/
        else
            entry.next = entry_30_; /*不是当前的第一个entry对象*/
        entry_31_.recordRemoval(this);
        return entry_31_;
        }
        entry = entry_31_;
    }
    return entry_31_; /*返回删除的entry对象的value*/
    }
   /*和上面的removeEntryForKey 原理类似*/
    final Entry removeMapping(Object object) {
    if (!(object instanceof Map.Entry)) /*先判断类型是否相同*/
        return null;
    Map.Entry entry = (Map.Entry) object; /*此传入的object就是一个对象类型了,强制转换成entry类型*/
    Object object_33_ = entry.getKey(); /*得到key*/
    /*得到hash值*/
    int i = object_33_ == null ? 0 : hash(object_33_.hashCode());
    /*得到在table数组里的定位*/
    int i_34_ = indexFor(i, table.length);
    Entry entry_35_ = table[i_34_];
    Entry entry_36_;
    Entry entry_37_;
    /*实现原理和上面的方法一致,就不细说了*/
    for (entry_37_ = entry_35_; entry_37_ != null; entry_37_ = entry_36_) {
        entry_36_ = entry_37_.next;
        if (entry_37_.hash == i && entry_37_.equals(entry)) {
        modCount++;
        size--;
        if (entry_35_ == entry_37_)
            table[i_34_] = entry_36_;
        else
            entry_35_.next = entry_36_;
        entry_37_.recordRemoval(this);
        return entry_37_;
        }
        entry_35_ = entry_37_;
    }
    return entry_37_;
    }
    /*clear方法,遍历table数组将每一个entry对象置为null,等待虚拟机将其回收*/
    public void clear() {
    modCount++;
    Entry[] entrys = table;
    for (int i = 0; i < entrys.length; i++)
        entrys[i] = null;
    size = 0; /*将size置为0*/
    }
    /*object代表的是value的值*/
    public boolean containsValue(Object object) {
    if (object == null)
        return containsNullValue();
    Entry[] entrys = table;
    /*用两个for循环来遍历,其实效率不高啦*/
    for (int i = 0; i < entrys.length; i++) {
    /*防止有出现链表的情况,所以在每个table数组的位置在遍历一次,逐个对比*/
        for (Entry entry = entrys[i]; entry != null; entry = entry.next) {
        if (object.equals(entry.value))
            return true; /*找到则返回true*/
        }
    }
    return false;
    }
    /*当传进来的value等于null时调用这个方法,原理和上面的方法一致*/
    private boolean containsNullValue() {
    Entry[] entrys = table;
    for (int i = 0; i < entrys.length; i++) {
        for (Entry entry = entrys[i]; entry != null; entry = entry.next) {
        if (entry.value == null)
            return true;
        }
    }
    return false;
    }
    /*用来克隆的方法,此方法比较简单*/
    public Object clone() {
    HashMap hashmap_38_ = null;/*新创建一个hashmap对象*/
    try {
        hashmap_38_ = (HashMap) super.clone();
    } catch (CloneNotSupportedException clonenotsupportedexception) {
        /* empty */
    }
    hashmap_38_.table = new Entry[table.length];/*创建一个新的table*/
    hashmap_38_.entrySet = null;
    hashmap_38_.modCount = 0; /*将它设为0是因为putAllForCreate(this)方法会在内部进行modCount++ */
    hashmap_38_.size = 0;
    hashmap_38_.init();
    hashmap_38_.putAllForCreate(this);
    return hashmap_38_; /最后返回此hashmap对象/
    }
    /*此方法在指定的地方添加一个新的对象,指定的地方为 i_40_*/
    void addEntry(int i, Object object, Object object_39_, int i_40_) {
    Entry entry = table[i_40_];
    table[i_40_] = new Entry(i, object, object_39_, entry); /*这句代码将新加的对象加到table[i_40_]处*/
    /*进行容量大小判定,如果因为多加一个对象而超出容量,则扩容*/
    if (size++ >= threshold)
        resize(2 * table.length);
    }
    /*原理同上*/
    void createEntry(int i, Object object, Object object_41_, int i_42_) {
    Entry entry = table[i_42_];
    table[i_42_] = new Entry(i, object, object_41_, entry);
    size++;
    }

    Iterator newKeyIterator() {
    return new KeyIterator(null);
    }

    Iterator newValueIterator() {
    return new ValueIterator(null);
    }

    Iterator newEntryIterator() {
    return new EntryIterator(null);
    }

    public Set keySet() {
    Set set = keySet;
    return set != null ? set : (keySet = new KeySet(null));
    }

    public Collection values() {
    Collection collection = values;
    return collection != null ? collection : (values = new Values(null));
    }
    /*entrySet集合*/
    public Set entrySet() {
    return entrySet0();
    }

    private Set entrySet0() {
    Set set = entrySet;
    return set != null ? set : (entrySet = new EntrySet(null));
    }
    /*下面两个方法我几乎没用过,建议去百度看看其他大神的解释,我这就不多说了*/
    private void writeObject(ObjectOutputStream objectoutputstream)
    throws IOException {
    Iterator iterator = size > 0 ? entrySet0().iterator() : null;
    objectoutputstream.defaultWriteObject();
    objectoutputstream.writeInt(table.length);
    objectoutputstream.writeInt(size);
    if (iterator != null) {
        while (iterator.hasNext()) {
        Map.Entry entry = (Map.Entry) iterator.next();
        objectoutputstream.writeObject(entry.getKey());
        objectoutputstream.writeObject(entry.getValue());
        }
    }
    }

    private void readObject(ObjectInputStream objectinputstream)
    throws IOException, ClassNotFoundException {
    objectinputstream.defaultReadObject();
    int i = objectinputstream.readInt();
    table = new Entry[i];
    init();
    int i_43_ = objectinputstream.readInt();
    for (int i_44_ = 0; i_44_ < i_43_; i_44_++) {
        Object object = objectinputstream.readObject();
        Object object_45_ = objectinputstream.readObject();
        putForCreate(object, object_45_);
    }
    }

    int capacity() {
    return table.length;
    }

    float loadFactor() {
    return loadFactor;
    }
}

HashSet源码及分析 因为hashset实际上就是hashmap的封装,所以它内容很少,基本很多方法都是直接用hashmap里的方法,不过只是hashset里面的value值是不重复的而已

/*
 可以看到,hashset继承了AbstractSet接口,实现了Set,Cloneable, Serializable接口
*/
public class HashSet extends AbstractSet
    implements Set, Cloneable, Serializable
{
/*
serialVersionUID序列id,
transient HashMap map   说一下transient 。transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。然而非transient型的变量是被包括进去的。我们也可以看到,Hashset里有以HashMap定义的map,可以说,HashSet实际上就是用HashMap来实现的
*/
    static final long serialVersionUID = -5024744406713321676L;
    private transient HashMap map;
    /*HashSet里的value就是PRESENT对象,*/
    private static final Object PRESENT = new Object();
    /*默认构造函数,创建出一个HashMap对象,以HashMap默认的16容量和0.75的负载因子创建*/
    public HashSet() {
    map = new HashMap();
    }
    /*传入collection集合对象来创建一个map对象,也是使用的是hashmap里的一个构造函数来创建map对象*/
    public HashSet(Collection collection) {
    map = new HashMap(Math.max(((int) ((float) collection.size() / 0.75F)
                    + 1),
                   16));
    addAll(collection);/*addall() hashmap里的静态方法*/
    }
    /*以下几个都是hashmap的构造函数,大家看看就知道什么意思了,后面的代码里会说*/
    public HashSet(int i, float f) {
    map = new HashMap(i, f);
    }

    public HashSet(int i) {
    map = new HashMap(i);
    }

    HashSet(int i, float f, boolean bool) {
    map = new LinkedHashMap(i, f);
    }
    /*Iterator迭代器,用来迭代出keySet里的值*/
    public Iterator iterator() {
    return map.keySet().iterator();
    }
    /*map的大小*/
    public int size() {
    return map.size();
    }
    /*判断是否为空*/
    public boolean isEmpty() {
    return map.isEmpty();
    }
    /*由于hashset里面只存value,所以contains方法里直接调用map里的containsKey()方法就行了,因为其实hashmap里的key集合就是一个hashset,key的值是不会重复的*/
    public boolean contains(Object object) {
    return map.containsKey(object);
    }
    /*add方法,调用map的put方法,上面hashmap里已经解释过了*/
    public boolean add(Object object) {
    return map.put(object, PRESENT) == null;
    }
    /*和hashmap的remove方法原理一样的*/
    public boolean remove(Object object) {
    return map.remove(object) == PRESENT;
    }
    /*和hashmap的clear的实现步骤是一样的*/
    public void clear() {
    map.clear();
    }
    /*基本上都是直接用的hashmap的clone方法*/
    public Object clone() {
    HashSet hashset_0_;
    try {
        HashSet hashset_1_ = (HashSet) super.clone();
        hashset_1_.map = (HashMap) map.clone();
        hashset_0_ = hashset_1_;
    } catch (CloneNotSupportedException clonenotsupportedexception) {
        throw new InternalError();
    }
    return hashset_0_;
    }

    private void writeObject(ObjectOutputStream objectoutputstream)
    throws IOException {
    objectoutputstream.defaultWriteObject();
    objectoutputstream.writeInt(map.capacity());
    objectoutputstream.writeFloat(map.loadFactor());
    objectoutputstream.writeInt(map.size());
    Iterator iterator = map.keySet().iterator();
    while (iterator.hasNext())
        objectoutputstream.writeObject(iterator.next());
    }

    private void readObject(ObjectInputStream objectinputstream)
    throws IOException, ClassNotFoundException {
    objectinputstream.defaultReadObject();
    int i = objectinputstream.readInt();
    float f = objectinputstream.readFloat();
    map = (this instanceof LinkedHashSet
           ? (HashMap) new LinkedHashMap(i, f) : new HashMap(i, f));
    int i_2_ = objectinputstream.readInt();
    for (int i_3_ = 0; i_3_ < i_2_; i_3_++) {
        Object object = objectinputstream.readObject();
        map.put(object, PRESENT);
    }
    }
}

分析完了hashmap和hashset的源码,我们来总结一下他们的遍历方式吧。
1:hashmap遍历的方式
第一种:
  Map map = new HashMap();
  Iterator iter = map.entrySet().iterator();
  while (iter.hasNext()) {
  Map.Entry entry = (Map.Entry) iter.next();
  Object key = entry.getKey();
  Object val = entry.getValue();
  }
  效率高,以后一定要使用此种方式!

第二种:
  Map map = new HashMap();
  Iterator iter = map.keySet().iterator();
  while (iter.hasNext()) {
  Object key = iter.next();
  Object val = map.get(key);
  }
  效率低,以后尽量少使用!
2:hashset的遍历方式
hashset遍历的方式很单一,就是直接使用迭代器来遍历

Set set = new HashSet(); //集合都可以用Iterator来遍历
Iterator it = set.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
hashmap和hashset的源码和分析就到这里了,第一次写博客,可能有很多地方写的不好,要是有写的不对的地方,欢迎前来指正!谢谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值