集合框架(HashSet存储字符串并遍历) HashSet保证元素唯一性的源码解析

核心代码:

package com.wayboo;

import java.util.HashSet;

/*
 * HashSet:存储字符串并遍历
 * 问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?
 * 通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。
 * 步骤:
 *      首先比较哈希值
 *      如果相同,继续走,比较地址值或者走equals()
 *      如果不同,就直接添加到集合中  
 * 按照方法的步骤来说:   
 *      先看hashCode()值是否相同
 *          相同:继续走equals()方法
 *              返回true: 说明元素重复,就不添加
 *              返回false:说明元素不重复,就添加到集合
 *          不同:就直接把元素添加到集合
 * 如果类没有重写这两个方法,默认使用的Object()。一般来说不同相同。
 * 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
 */
public class HashSetDemo {
public static void main(String[] args) {
    // 创建集合对象
    HashSet<String> hs = new HashSet<String>();

    // 创建并添加元素
    hs.add("hello");
    hs.add("world");
    hs.add("java");
    hs.add("world");

    // 遍历集合
    for (String s : hs) {
        System.out.println(s);
        }
    }
}

集合框架(HashSet保证元素唯一性的源码解析)

 interface Collection {
...
}

interface Set extends Collection {
...
}

class HashSet implements Set {
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;

public HashSet() {
    map = new HashMap<>();
}

public boolean add(E e) { //e=hello,world
    return map.put(e, PRESENT)==null;
   }
}

class HashMap implements Map {
public V put(K key, V value) { //key=e=hello,world

    //看哈希表是否为空,如果空,就开辟空间
    if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }
    
    //判断对象是否为null
    if (key == null)
        return putForNullKey(value);
    
    int hash = hash(key); //和对象的hashCode()方法相关
    
    //在哈希表中查找hash值
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        //这次的e其实是第一次的world
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
            //走这里其实是没有添加元素
        }
    }

    modCount++;
    addEntry(hash, key, value, i); //把元素添加
    return null;
}

transient int hashSeed = 0;

final int hash(Object k) { //k=key=e=hello,
    int h = hashSeed;
    if (0 != h && k instanceof String) {
        return sun.misc.Hashing.stringHash32((String) k);
    }

    h ^= k.hashCode(); //这里调用的是对象的hashCode()方法

    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
         }
}


hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,705评论 25 709
  • 刚刚获悉《通往财富自由之路》得到订阅量超过了16万。我们是在“通往财富自由”还是在“创造财富自由”呢?我想后者的可...
    水平生阅读 253评论 0 0
  • 生长习性 鹤望兰属亚热带长日照植物,其喜温暖、湿润、阳光充足的环境,忌酷热、忌旱、忌涝,要求排水良好的疏松、肥沃、...
    生活浪客阅读 411评论 0 0
  • 我们每个人估计都有自己喜欢的人,有的已成恋人,有的还在苦苦追求,或是默默无言只是注视着她!这些都无可厚非,只是我想...
    姑射子宁阅读 3,320评论 0 0
  • 《黄昏》 车水马龙 人流中 总有熟悉的身影 匆匆而过 看, 这一盏儿咖啡时刻
    无墨水阅读 148评论 0 0