HashMap,HashTable,CurrentHashMap和HashSet的介绍

首先看HashMap,他是最基础的

他的内部结构首先是一个装着结点的数组,然后每一个结点又有下一个结点,也就是一个链表,好像是叫 链表散列 结构

  //数组
  //transient关键字表示在对象序列化的时候忽略该属性
  transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
 //结点的数据结构
  final K key;
  V value;
  Entry<K,V> next;
  int hash;

注意下面的equals方法,传进去的参数为Object类型,所以你如果自定义了equals方法,但是参数不是Object,那就是重载,不是覆盖,不会被调用

 public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            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;
    }

当往HashMap里面存储值的时候,会先判断容量是否足够,不够的时候会扩大容量
然后判断键是否为空,若为空则调用return putForNullKey(value);

或不为空则先把key的hash值再hash一次,此算法加入了高位计算,防止低位不变,高位变化时,造成的hash冲突。但代码里写的是hash(key)对吧,点进去看他的实现就可以看到是对他的hashcode再hash,我的是jdk1.7,好像在之前的是直接写的hash(key.hashcode);

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

        h ^= k.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);
    }

然后根据这个值计算他在数组中对应的下标。我们想到的就是对数组长度取模,但是不是这样做的

  */
    static int indexFor(int h, int length) {
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
        return h & (length-1);
    }

然后对该下标所对应的链表进行遍历,
若存在,改变value,返回,若不存在,把key和value放入,返回null。

放在最前面,在前面,最前面

之前在网上看到判断是否存在是先判断hashcode,若相等再调用equals方法,但是看实际的源码应该不是这样做的。

 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) 

这里的hash也不是之前的hashcode,是再hash过的。
而且若hash值相等,也不是调用的equals方法,而是直接用的==运算符
equals作为单独的一个判断条件(若equals成立,那么hashcode必定相等)。

get方法与put方法类似,进行查找然后返回即可。


HashTable是线程安全的HashMap,但是速度比较慢,他和HashMap的一个区别是他不能存放NULL键,他使用的hash值就是hashCode方法得出的hash值,而HashMap的hash值是再次计算过的

int hash = key.hashCode();
int hash = hash(key);

CurrentHashMap
是为了满足人们的欲望,既要线程安全,又要速度快。
他把一个大的map分为几个小的,然后在每一个小的map里实现线程安全,加快了速度。

在put时首先计算他属于那一段,然后在如同hashmap一样操作

读操作:使用volatile关键字,保证获取到的是最新的值
写操作:它会先获取该Key-Value对所在的Segment的锁,获取成功后就可以像操作一个普通的HashMap一样操作该Segment,并保证该Segment的安全性。

获取锁时,并不直接使用lock来获取,因为该方法获取锁失败时会挂起(参考可重入锁)。事实上,它使用了自旋锁,如果tryLock获取锁失败,说明锁被其它线程占用,此时通过循环再次以tryLock的方式申请锁。如果在循环过程中该Key所对应的链表头被修改,则重置retry次数。如果retry次数超过一定值,则使用lock方法申请锁。


HashSet
它里面实际上就是采用的HashMap,把值当作map的键
值用的是一个Object

//HashSet里面的每一个值当作key,然后值就是这个Object
private static final Object PRESENT = new Object();
    //HashSet中的HashMap
    private transient HashMap<E,Object> map;

如有错误,欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值