JDK8之HashMap的简单源码分析

先来了解一下HashMap的简单数据结构:


A0057DF797AC4EB628A05CAC4433A1E7.png

当HashMap的数据特别多的时候,链表会自动转换成红黑树:


5452B21E-E360-4768-ACEA-82943649351B.png

话不多说,直接上源码

   /**
     * HashMap实现了Cloneable,Serializable,
     * 说明创建一个HashMap不仅仅可以通过new的方式,
     * 还可以通过clone()和反序列化的方式创建
     */
    public class HashMap<K, V> extends AbstractMap<K, V>
            implements Map<K, V>, Cloneable, Serializable {

        private static final long serialVersionUID = 362498820763181265L;

        /**
         * 初始化的默认容量大小,小于16的默认为16,所以不要设置小于16的初始化参数
         */
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

        /**
         * 最大的容量
         */
        static final int MAXIMUM_CAPACITY = 1 << 30;

        /**
         * 加载因子,默认0.75
         */
        static final float DEFAULT_LOAD_FACTOR = 0.75f;

        /**
         * 当单个链表长度大于等于8的时候,就会转换成红黑树
         */
        static final int TREEIFY_THRESHOLD = 8;

        /**
         * 当单个链表长度小于等于6的时候,红黑树会转换会链表
         */
        static final int UNTREEIFY_THRESHOLD = 6;

        /**
         * 如果tab数组大小大于64,链表才会转换成红黑树
         */
        static final int MIN_TREEIFY_CAPACITY = 64;

        /**
         * HashMap中的最基本的一个数据单元。
         * 每一个Node对应我们存储的一个键值对
         */
        static class Node<K, V> implements Map.Entry<K, V> {
            /**
             * key对应的hash值
             */
            final int hash;
            /**
             * 存储的key值
             */
            final K key;
            /**
             * 存储的value值
             */
            V value;
            /**
             * 指向下一个Node
             */
            Node<K, V> next;

            /**
             * 构造函数
             *
             * @param hash
             * @param key
             * @param value
             * @param next
             */
            Node(int hash, K key, V value, Node<K, V> next) {
                this.hash = hash;
                this.key = key;
                this.value = value;
                this.next = next;
            }

            public final K getKey() {
                return key;
            }

            public final V getValue() {
                return value;
            }

            public final String toString() {
                return key + "=" + value;
            }

            /**
             * 计算Node的hashCode
             *
             * @return
             */
            public final int hashCode() {
                return Objects.hashCode(key) ^ Objects.hashCode(value);
            }

            /**
             * 替换Node里面的value值,并且返回旧value
             *
             * @param newValue
             * @return
             */
            public final V setValue(V newValue) {
                V oldValue = value;
                value = newValue;
                return oldValue;
            }

            /**
             * 重写Node的equals方法。
             * 类型相同的前提下,key值和value值相同才返回true
             *
             * @param o
             * @return
             */
            public final boolean equals(Object o) {
                if (o == this)
                    return true;
                if (o instanceof Map.Entry) {
                    Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
                    if (Objects.equals(key, e.getKey()) &&
                            Objects.equals(value, e.getValue()))
                        return true;
                }
                return false;
            }
        }

        /**
         * 计算key的hash值,决定了Node应该存放在tab的哪个索引位置
         *
         * @param key
         * @return
         */
        static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }

        /**
         * 判断x是否实现了Comparable接口,如果实现了的话,返回x的运行时类型
         * 否则返回null
         * 例如:class A implements Comparable<A>{}  返回A.class
         * <p>
         * class A implements Comparable<B>{}  返回null
         * <p>
         * class A implements Comparable<Object>{}  返回null
         * <p>
         * class A{}  返回null
         *
         * @param x
         * @return
         */
        static Class<?> comparableClassFor(Object x) {
            /**
             * 要求x一定是实现了Comparable接口的,否则返回null。
             */
            if (x instanceof Comparable) {
                Class<?> c;
                Type[] ts, as;
                Type t;
                ParameterizedType p;
                /**
                 * 如果x是String类型的,就直接返回String.class
                 */
                if ((c = x.getClass()) == String.class) // bypass checks
                    return c;
                /**
                 * 获取x直接实现的所有接口(ps:继承的不算)
                 * 例如:class A implements Comparable<A>{}  返回A.class
                 * 注意:一定要保证Comparable里面的泛型对象和当前对象类型一致,否则返回null
                 */
                if ((ts = c.getGenericInterfaces()) != null) {
                    for (int i = 0; i < ts.length; ++i) {
                        if (((t = ts[i]) instanceof ParameterizedType) &&
                                ((p = (ParameterizedType) t).getRawType() ==
                                        Comparable.class) &&
                                (as = p.getActualTypeArguments()) != null &&
                                as.length == 1 && as[0] == c) // type arg is c
                            return c;
                    }
                }
            }
            return null;
        }

        /**
         * 如果x的类型是指定的kc类型的话,就返回k.compareTo(x),否则返回0
         * <p>
         * 例如:compareComparables(String.class,"B","A")
         * 如果"A"的类型是String的话,就对"A"和"B"进行比较
         *
         * @param kc
         * @param k
         * @param x
         * @return
         */
        static int compareComparables(Class<?> kc, Object k, Object x) {
            return (x == null || x.getClass() != kc ? 0 :
                    ((Comparable) k).compareTo(x));
        }

        /**
         * 根据给定的cap计算一个合适的目标值。用于计算容器的容量值,始终保持返回的结果是2的整数次幂
         * <p>
         * 例如:给定一个cap=10,返回:16
         * cap=12,返回:16
         * cap=8,返回:8
         * cap=20,返回:32
         *
         * @param cap
         * @return
         */
        static final int tableSizeFor(int cap) {
            int n = cap - 1;
            n |= n >>> 1;
            n |= n >>> 2;
            n |= n >>> 4;
            n |= n >>> 8;
            n |= n >>> 16;
            return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
        }


        /**
         * 真正的Node容器,存放所有的Node节点
         */
        transient Node<K, V>[] table;

        /**
         * 键值对集合
         */
        transient Set<Entry<K, V>> entrySet;

        /**
         * HashMap里面所有的节点的数量
         */
        transient int size;

        /**
         * 记录HashMap的数据变化次数(不包括更新,添加和删除才会记录)。用于在迭代过程中判断是否被其他线程修改。
         * 如果在迭代过程中发现有其他线程修改数据,就抛出ConcurrentModificationException.
         */
        transient int modCount;

        /**
         * 扩容阀值。如果size>threshold,触发扩容机制
         * 例如:加载因子是0.75,当前最大容量是16,那么threshold=0.75*16=12
         * 当HashMap存储的键值对超过12的时候,触发扩容
         */
        int threshold;

        /**
         * 加载因子。默认0.75
         */
        final float loadFactor;

        /**
         * 构造函数。设置初始化容量和加载因子
         * <p>
         * 例如:new HashMap(32,0.8);
         * 设置初始化容量为32,加载因子为0.8。
         * 意味着当键值对数量超过32*0.8的时候触发扩容
         * <p>
         * 优化:
         * 如果事先能确定自己需要多大的容量,可以利用这个构造函数设置好初始化容量,避免扩容,提供性能
         * 注意:如果确定好需要30大小的容量,可以这样:new HashMap(32,1);
         * 因为当数量达到32*1=32的时候,才会触发扩容
         *
         * @param initialCapacity
         * @param loadFactor
         */
        public HashMap(int initialCapacity, float loadFactor) {
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal initial capacity: " +
                        initialCapacity);
            if (initialCapacity > MAXIMUM_CAPACITY)
                initialCapacity = MAXIMUM_CAPACITY;
            if (loadFactor <= 0 || Float.isNaN(loadFactor))
                throw new IllegalArgumentException("Illegal load factor: " +
                        loadFactor);
            this.loadFactor = loadFactor;
            //如果不是2的整数次幂,就转换成2的整数次幂
            this.threshold = tableSizeFor(initialCapacity);
        }

        /**
         * 构造函数。设置初始化容量,默认加载因子为0.75
         * <p>
         * 例如:new HashMap(32);
         * 设置初始化容量为32,加载因子为0.75。
         * 意味着当键值对数量超过32*0.75的时候触发扩容
         * <p>
         * 优化:
         * 如果事先能确定自己需要多大的容量,可以利用这个构造函数设置好初始化容量,避免扩容,提供性能
         * 注意:如果确定好需要30大小的容量,需要设置初始容量为64:new HashMap(64);而不是new HashMap(32);
         * 因为当数量达到32*0.75=24的时候,就会触发扩容,所以需要设置成64
         *
         * @param initialCapacity
         */
        public HashMap(int initialCapacity) {
            this(initialCapacity, DEFAULT_LOAD_FACTOR);
        }

        /**
         * 构造函数。
         * <p>
         * 加载因子默认0.75
         * 初始容量默认16
         */
        public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR;
        }

        /**
         * 构造函数。
         * <p>
         * 就是复制另外一个map的数据
         *
         * @param m
         */
        public HashMap(Map<? extends K, ? extends V> m) {
            this.loadFactor = DEFAULT_LOAD_FACTOR;
            putMapEntries(m, false);
        }


        /**
         * @param m
         * @param evict
         */
        final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
            int s = m.size();
            if (s > 0) {
                /**
                 * 判断数组是否初始化
                 */
                if (table == null) { // pre-size

                    float ft = ((float) s / loadFactor) + 1.0F;
                    /**
                     * 计算t的值
                     */
                    int t = ((ft < (float) MAXIMUM_CAPACITY) ?
                            (int) ft : MAXIMUM_CAPACITY);
                    /**
                     * 如果t大于threshold,更新threshold
                     */
                    if (t > threshold)
                        threshold = tableSizeFor(t);
                }
                //触发扩容
                else if (s > threshold)
                    resize();

                /**
                 * 通过循环的方式将m的数据给到目标对象
                 */
                for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                    K key = e.getKey();
                    V value = e.getValue();
                    putVal(hash(key), key, value, false, evict);
                }
            }
        }

        /**
         * 获取HashMap的键值对数量
         * @return
         */
        public int size() {
            return size;
        }

        /**
         * 判断HashMap是否为空
         * @return
         */
        public boolean isEmpty() {
            return size == 0;
        }

        /**
         * 根据指定的key获取数据value
         * @param key
         * @return
         */
        public V get(Object key) {
            Node<K,V> e;
            return (e = getNode(hash(key), key)) == null ? null : e.value;
        }

        /**
         * 根据hash值和key找到对应的Node节点
         * @param hash
         * @param key
         * @return
         */
        final Node<K,V> getNode(int hash, Object key) {
            Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
            /**
             * 先通过hash值找到数组中的槽位,也就是索引值:first = tab[(n - 1) & hash])
             */
            if ((tab = table) != null && (n = tab.length) > 0 &&
                    (first = tab[(n - 1) & hash]) != null) {
                /**
                 * 先判断第一个Node是不是要找的目标对象,如果是就直接返回
                 */
                if (first.hash == hash && // always check first node
                        ((k = first.key) == key || (key != null && key.equals(k))))
                    return first;
                /**
                 * 如果第一个不是要找的目标对象,就开始遍历
                 */
                if ((e = first.next) != null) {
                    /**
                     * 如果是红黑树的数据结构,就使用红黑树的查询方式
                     */
                    if (first instanceof TreeNode)
                        return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                    /**
                     * 否则就是链表,那就遍历链表查找目标对象
                     */
                    do {
                        /**
                         * hash值相等并且key相同才是目标对象
                         */
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                            return e;
                    } while ((e = e.next) != null);
                }
            }
            return null;
        }

        /**
         * 判断是否存在这个key
         * @param key
         * @return
         */
        public boolean containsKey(Object key) {
            return getNode(hash(key), key) != null;
        }

        /**
         * 存放键值对
         * @param key
         * @param value
         * @return
         */
        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }

        /**
         * 存放键值对
         * @param hash
         * @param key
         * @param value
         * @param onlyIfAbsent
         * @param evict
         * @return
         */
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;
            /**
             * 如果tab没有初始化,就先初始化
             */
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            /**
             * 如果hash对应的索引位置还是null,就直接给这个索引位置创建一个Node
             */
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            /**
             * 剩下的情况就是索引位置有值,那么分几种情况:
             * 1.索引上的Node节点的hash和key正好和我们需要put的hash和key一直,那就要更新value
             * 2.如果索引上的Node和我们需要put的hash和key不一样的话,那就要开始遍历后面的节点,并且重复上面的判断
             * 2.1:如果节点是一颗红黑树的话,那就通过putTreeVal更新或者添加数据
             * 2.2:如果节点是链表的话,就循环判断,决定更新或者添加数据
             */
            else {
                Node<K,V> e; K k;
                /**
                 * 判断第一个Node节点
                 */
                if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                    e = p;
                /**
                 * 如果是红黑树
                 */
                else if (p instanceof TreeNode)
                    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                /**
                 * 如果是链表
                 */
                else {
                    for (int binCount = 0; ; ++binCount) {
                        if ((e = p.next) == null) {
                            p.next = newNode(hash, key, value, null);
                            /**
                             * 如果链表数量大于TREEIFY_THRESHOLD(默认是8),将链表转换成红黑树
                             */
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                /**
                 * 如果找到了目标对象
                 */
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    /**
                     * 更新目标对象的value
                     */
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;
                    //啥都没做,留给LinkedHashMap
                    afterNodeAccess(e);
                    //如果时修改数据,返回旧数据
                    return oldValue;
                }
            }
            //记录添加Node次数
            ++modCount;
            /**
             * 添加数据后size大于threshold时,开始扩容
             */
            if (++size > threshold)
                resize();
            //啥都没做,留给LinkedHashMap
            afterNodeInsertion(evict);
            //如果时添加数据的话,返回null
            return null;
        }

        /**
         * 扩容
         * @return
         */
        final Node<K,V>[] resize() {
            /**
             * 拿到原数组,后面要用来转换数据
             */
            Node<K,V>[] oldTab = table;
            int oldCap = (oldTab == null) ? 0 : oldTab.length;
            int oldThr = threshold;
            int newCap, newThr = 0;
            if (oldCap > 0) {
                /**
                 * 如果达到最大容量,那就没法扩容了,直接返回原数组
                 */
                if (oldCap >= MAXIMUM_CAPACITY) {
                    threshold = Integer.MAX_VALUE;
                    return oldTab;
                }
                /**
                 * 初始化新的扩容阀值
                 */
                else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                        oldCap >= DEFAULT_INITIAL_CAPACITY)
                    newThr = oldThr << 1; // double threshold
            }
            /**
             * 初始化新容量
             */
            else if (oldThr > 0) // initial capacity was placed in threshold
                newCap = oldThr;
            /**
             * 初始化新容量和新的扩容阀值,都是给默认值
             */
            else {               // zero initial threshold signifies using defaults
                newCap = DEFAULT_INITIAL_CAPACITY;
                newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
            }
            /**
             * 重新校正新的扩容阀值
             */
            if (newThr == 0) {
                float ft = (float)newCap * loadFactor;
                newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                        (int)ft : Integer.MAX_VALUE);
            }
            /**
             * 前面都是为了计算新的容量和扩容阀值
             */
            //设置扩容阀值
            threshold = newThr;
            /**
             * 开始扩容。先创建一个指定大小的Node数组,并赋值给table
             */
            @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
            table = newTab;
            /**
             * 判断原数组不为空
             */
            if (oldTab != null) {
                /**
                 * 开始循环数组的每一个Node对象,里面的每一个Node有可能是链表,也有可能是红黑树
                 */
                for (int j = 0; j < oldCap; ++j) {
                    Node<K,V> e;
                    /**
                     * 判断拿到的指定索引位置的Node节点不为空
                     */
                    if ((e = oldTab[j]) != null) {
                        oldTab[j] = null;
                        /**
                         * 如果e.next为空,说明只有一个Node节点,直接转移就可以
                         */
                        if (e.next == null)
                            newTab[e.hash & (newCap - 1)] = e;
                        /**
                         * 如果是红黑树,调用红黑树的一个数据转移的方法
                         */
                        else if (e instanceof TreeNode)
                            ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                        /**
                         * 如果是链表,循环遍历并转移
                         */
                        else { // preserve order
                            Node<K,V> loHead = null, loTail = null;
                            Node<K,V> hiHead = null, hiTail = null;
                            Node<K,V> next;
                            do {
                                next = e.next;
                                if ((e.hash & oldCap) == 0) {
                                    if (loTail == null)
                                        loHead = e;
                                    else
                                        loTail.next = e;
                                    loTail = e;
                                }
                                else {
                                    if (hiTail == null)
                                        hiHead = e;
                                    else
                                        hiTail.next = e;
                                    hiTail = e;
                                }
                            } while ((e = next) != null);
                            if (loTail != null) {
                                loTail.next = null;
                                newTab[j] = loHead;
                            }
                            if (hiTail != null) {
                                hiTail.next = null;
                                newTab[j + oldCap] = hiHead;
                            }
                        }
                    }
                }
            }
            /**
             * 返回新的扩容后的数组
             */
            return newTab;
        }

        /**
         * 将链表转换成红黑树
         * @param tab
         * @param hash
         */
        final void treeifyBin(Node<K,V>[] tab, int hash) {
            int n, index; Node<K,V> e;
            /**
             * 如果这个数组的长度小于64,就直接扩容,并不会转换成红黑树
             */
            if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
                resize();
            /**
             * 找到指定hash对应的索引位置的Node节点,将它转换成红黑树
             */
            else if ((e = tab[index = (n - 1) & hash]) != null) {
                TreeNode<K,V> hd = null, tl = null;
                /**
                 * 循环遍历
                 */
                do {
                    /**
                     * 构造一棵树,replacementTreeNode只是调用了new TreeNode()构造函数
                     */
                    TreeNode<K,V> p = replacementTreeNode(e, null);
                    if (tl == null)
                        hd = p;
                    /**
                     * 双向链表
                     */
                    else {
                        p.prev = tl;
                        tl.next = p;
                    }
                    tl = p;
                } while ((e = e.next) != null);
                /**
                 * 将新的TreeNode给到对应的索引位置,将单向链表变成来双向链表
                 */
                if ((tab[index] = hd) != null)
                    //这里才是构建真正的红黑树
                    hd.treeify(tab);
            }
        }

        /**
         * 将m中的数据put进当前HashMap
         * @param m
         */
        public void putAll(Map<? extends K, ? extends V> m) {
            putMapEntries(m, true);
        }

        /**
         * 移除指定的key对应的Node,并返回被移除的value
         * @param key
         * @return
         */
        public V remove(Object key) {
            Node<K,V> e;
            return (e = removeNode(hash(key), key, null, false, true)) == null ?
                    null : e.value;
        }

        /**
         * 移除指定Node节点
         * @param hash
         * @param key
         * @param value
         * @param matchValue
         * @param movable
         * @return
         */
        final Node<K,V> removeNode(int hash, Object key, Object value,
                                   boolean matchValue, boolean movable) {
            Node<K,V>[] tab; Node<K,V> p; int n, index;
            /**
             * 数组不为空,并且hash指定的位置有Node节点
             */
            if ((tab = table) != null && (n = tab.length) > 0 &&
                    (p = tab[index = (n - 1) & hash]) != null) {
                Node<K,V> node = null, e; K k; V v;
                /**
                 * 先判断第一个Node节点是否是目标对象
                 */
                if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                    node = p;
                /**
                 * 如果第一个Node不是目标对象
                 */
                else if ((e = p.next) != null) {
                    /**
                     * 如果是红黑树,就找到指定的TreeNode节点
                     */
                    if (p instanceof TreeNode)
                        node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                    /**
                     * 如果是链表,就循环遍历找到目标对象
                     */
                    else {
                        do {
                            if (e.hash == hash &&
                                    ((k = e.key) == key ||
                                            (key != null && key.equals(k)))) {
                                node = e;
                                break;
                            }
                            p = e;
                        } while ((e = e.next) != null);
                    }
                }
                /**
                 * 如果找到来目标对象。matchValue表示是否要在value也相等的情况下才删除
                 */
                if (node != null && (!matchValue || (v = node.value) == value ||
                        (value != null && value.equals(v)))) {
                    /**
                     * 如果目标对象是在红黑树中,那就调用removeTreeNode移除
                     */
                    if (node instanceof TreeNode)
                        ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                    /**
                     * 如果第一个Node节点就是目标对象,那就直接把next节点放在索引位置上
                     */
                    else if (node == p)
                        tab[index] = node.next;
                    /**
                     * 否则就是链表,直接替换p.next
                     */
                    else
                        p.next = node.next;
                    //记录修改次数
                    ++modCount;
                    //减少size
                    --size;
                    //啥都没做,留给LinkedHashMap
                    afterNodeRemoval(node);
                    //返回删除的节点
                    return node;
                }
            }
            return null;
        }

        /**
         * 清除HashMap的数据
         */
        public void clear() {
            Node<K,V>[] tab;
            modCount++;
            if ((tab = table) != null && size > 0) {
                /**
                 * 重置size
                 */
                size = 0;
                /**
                 * 循环将所有索引位置置空
                 */
                for (int i = 0; i < tab.length; ++i)
                    tab[i] = null;
            }
        }

        /**
         * 判断是否包含指定的value。直接遍历,比较粗暴,数据量大的时候性能不高
         * @param value
         * @return
         */
        public boolean containsValue(Object value) {
            Node<K,V>[] tab; V v;
            if ((tab = table) != null && size > 0) {
                /**
                 * 循环遍历数组
                 */
                for (int i = 0; i < tab.length; ++i) {
                    /**
                     * 再循环遍历索引下的每一个节点
                     */
                    for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                        /**
                         * 判断对应节点的value值是否和指定的value相同
                         */
                        if ((v = e.value) == value ||
                                (value != null && value.equals(v)))
                            return true;
                    }
                }
            }
            return false;
        }

        /**
         * 获取所有key的集合
         * @return
         */
        public Set<K> keySet() {
            Set<K> ks = keySet;
            if (ks == null) {
                ks = new KeySet();
                keySet = ks;
            }
            return ks;
        }

        final class KeySet extends AbstractSet<K> {
            /**
             * 直接使用HashMap对象的size
             * @return
             */
            public final int size()                 { return size; }

            /**
             * 直接调用HashMap的clear
             */
            public final void clear()               { HashMap.this.clear(); }

            /**
             * 返回一个key迭代器
             * @return
             */
            public final Iterator<K> iterator()     { return new KeyIterator(); }

            /**
             * 直接调用HashMap的containsKey
             * @param o
             * @return
             */
            public final boolean contains(Object o) { return containsKey(o); }

            /**
             * 直接调用HashMap的removeNode
             * @param key
             * @return
             */
            public final boolean remove(Object key) {
                return removeNode(hash(key), key, null, false, true) != null;
            }

            /**
             * 返回key分割迭代器对象,用于多线程遍历
             * @return
             */
            public final Spliterator<K> spliterator() {
                return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
            }

            public final void forEach(Consumer<? super K> action) {
                Node<K,V>[] tab;
                if (action == null)
                    throw new NullPointerException();
                if (size > 0 && (tab = table) != null) {
                    //遍历之前先拿到modCount的值
                    int mc = modCount;
                    for (int i = 0; i < tab.length; ++i) {
                        for (Node<K,V> e = tab[i]; e != null; e = e.next)
                            action.accept(e.key);
                    }
                    //对比遍历前后modCount的值,发生变化就抛异常。说明有其他线程修改了HashMap
                    if (modCount != mc)
                        throw new ConcurrentModificationException();
                }
            }
        }

        /**
         * 返回value集合
         * @return
         */
        public Collection<V> values() {
            Collection<V> vs = values;
            if (vs == null) {
                vs = new Values();
                values = vs;
            }
            return vs;
        }

        final class Values extends AbstractCollection<V> {
            /**
             * 返回HashMap的size
             * @return
             */
            public final int size()                 { return size; }

            /**
             * 清除所有的键值对
             */
            public final void clear()               { HashMap.this.clear(); }

            /**
             * 返回一个value迭代器
             * @return
             */
            public final Iterator<V> iterator()     { return new ValueIterator(); }

            /**
             * 判断是否包含指定的value
             * @param o
             * @return
             */
            public final boolean contains(Object o) { return containsValue(o); }

            /**
             * 返回value分割迭代器对象,用于多线程遍历
             * @return
             */
            public final Spliterator<V> spliterator() {
                return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
            }
            public final void forEach(Consumer<? super V> action) {
                Node<K,V>[] tab;
                if (action == null)
                    throw new NullPointerException();
                if (size > 0 && (tab = table) != null) {
                    //记录modCount
                    int mc = modCount;
                    /**
                     * 直接双重循环遍历
                     */
                    for (int i = 0; i < tab.length; ++i) {
                        for (Node<K,V> e = tab[i]; e != null; e = e.next)
                            action.accept(e.value);
                    }
                    //对比遍历前后的值,发生变化说明HashMap被修改
                    if (modCount != mc)
                        throw new ConcurrentModificationException();
                }
            }
        }

        /**
         * 设置entrySet=new EntrySet()并返回
         * @return
         */
        public Set<Map.Entry<K,V>> entrySet() {
            Set<Map.Entry<K,V>> es;
            return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
        }

        /**
         * 键值对结合
         */
        final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
            /**
             * 返回size
             * @return
             */
            public final int size()                 { return size; }

            /**
             * 清除所有的键值对
             */
            public final void clear()               { HashMap.this.clear(); }

            /**
             * 返回一个键值对迭代器
             * @return
             */
            public final Iterator<Map.Entry<K,V>> iterator() {
                return new EntryIterator();
            }

            /**
             * 判断是否包含指定的键值对
             * @param o
             * @return
             */
            public final boolean contains(Object o) {
                if (!(o instanceof Map.Entry))
                    return false;
                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
                Object key = e.getKey();
                Node<K,V> candidate = getNode(hash(key), key);
                return candidate != null && candidate.equals(e);
            }

            /**
             * 移除指定的键值对
             * @param o
             * @return
             */
            public final boolean remove(Object o) {
                if (o instanceof Map.Entry) {
                    Map.Entry<?,?> e = (Map.Entry<?,?>) o;
                    Object key = e.getKey();
                    Object value = e.getValue();
                    return removeNode(hash(key), key, value, true, true) != null;
                }
                return false;
            }

            /**
             * 返回Entry分割迭代器对象,用于多线程遍历
             * @return
             */
            public final Spliterator<Map.Entry<K,V>> spliterator() {
                return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
            }

            /**
             * 遍历键值对
             * @param action
             */
            public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
                Node<K,V>[] tab;
                if (action == null)
                    throw new NullPointerException();
                if (size > 0 && (tab = table) != null) {
                    int mc = modCount;
                    /**
                     * 双重循环遍历
                     */
                    for (int i = 0; i < tab.length; ++i) {
                        for (Node<K,V> e = tab[i]; e != null; e = e.next)
                            action.accept(e);
                    }
                    //对比前后的modCount,判断是否被修改
                    if (modCount != mc)
                        throw new ConcurrentModificationException();
                }
            }
        }


        // Overrides of JDK8 Map extension methods

        /**
         * 获取指定key对应的value,如果没有找到,就给默认值defaultValue
         * @param key
         * @param defaultValue
         * @return
         */
        @Override
        public V getOrDefault(Object key, V defaultValue) {
            Node<K,V> e;
            return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
        }

        /**
         * key不存在的时候,则添加
         * key存在的话,不做修改
         * @param key
         * @param value
         * @return
         */
        @Override
        public V putIfAbsent(K key, V value) {
            return putVal(hash(key), key, value, true, true);
        }

        /**
         * 移除指定的key和value
         * @param key
         * @param value
         * @return
         */
        @Override
        public boolean remove(Object key, Object value) {
            return removeNode(hash(key), key, value, true, true) != null;
        }

        /**
         * 找到key和value相关的目标Node,把oldValue替换成指定的newValue
         * @param key
         * @param oldValue
         * @param newValue
         * @return
         */
        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            Node<K,V> e; V v;
            if ((e = getNode(hash(key), key)) != null &&
                    ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
                e.value = newValue;
                //啥也没做,留给LinkedHashMap
                afterNodeAccess(e);
                return true;
            }
            return false;
        }

        /**
         * 更新指定的key对应的Node的value
         * @param key
         * @param value
         * @return
         */
        @Override
        public V replace(K key, V value) {
            Node<K,V> e;
            if ((e = getNode(hash(key), key)) != null) {
                V oldValue = e.value;
                e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
            return null;
        }

        /**
         * 通过key获取value,如果查询到了就返回value
         * 否则,调用mappingFunction.apply(key)创建一个value,将这个value放进HashMap中并返回
         * @param key
         * @param mappingFunction
         * @return
         */
        @Override
        public V computeIfAbsent(K key,
                                 Function<? super K, ? extends V> mappingFunction) {
            if (mappingFunction == null)
                throw new NullPointerException();
            /**
             * 计算key的hash值
             */
            int hash = hash(key);
            Node<K,V>[] tab; Node<K,V> first; int n, i;
            int binCount = 0;
            TreeNode<K,V> t = null;
            Node<K,V> old = null;
            /**
             * 如果满足扩容条件,就扩容
             */
            if (size > threshold || (tab = table) == null ||
                    (n = tab.length) == 0)
                n = (tab = resize()).length;
            /**
             * 拿到对应索引下的Node节点
             */
            if ((first = tab[i = (n - 1) & hash]) != null) {
                /**
                 * 如果是红黑树节点,就调用getTreeNode方法
                 */
                if (first instanceof TreeNode)
                    old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
                /**
                 * 如果是链表,就循环判断并获取
                 */
                else {
                    Node<K,V> e = first; K k;
                    do {
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k)))) {
                            old = e;
                            break;
                        }
                        ++binCount;
                    } while ((e = e.next) != null);
                }
                V oldValue;
                /**
                 * 如果能拿到value,就直接返回
                 */
                if (old != null && (oldValue = old.value) != null) {
                    afterNodeAccess(old);
                    return oldValue;
                }
            }
            /**
             * 调用mappingFunction获取一个value
             */
            V v = mappingFunction.apply(key);
            /**
             * 如果获取的value为空,就直接返回null
             */
            if (v == null) {
                return null;
            }
            /**
             * 如果前面查询的Node节点不为空,就更新它的value,并返回更新后的值
             */
            else if (old != null) {
                old.value = v;
                //啥也不做
                afterNodeAccess(old);
                return v;
            }
            /**
             * 如果第一个节点是红黑树节点,通过putTreeVal更新节点的value
             */
            else if (t != null)
                t.putTreeVal(this, tab, hash, key, v);
            /**
             * 如果第一个节点是链表,就创建一个Node节点放进当前链表中
             */
            else {
                tab[i] = newNode(hash, key, v, first);
                /**
                 * 如果满足转换红黑树的条件,就调用treeifyBin将链表转换成红黑树
                 */
                if (binCount >= TREEIFY_THRESHOLD - 1)
                    treeifyBin(tab, hash);
            }
            //记录修改的次数
            ++modCount;
            //size自增
            ++size;
            //啥也不做
            afterNodeInsertion(true);
            //返回新的value
            return v;
        }

        /**
         * 通过key找到node节点,
         * 找到就更新node的value,
         * 否则就删除指定的node
         * @param key
         * @param remappingFunction
         * @return
         */
        public V computeIfPresent(K key,
                                  BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            if (remappingFunction == null)
                throw new NullPointerException();
            Node<K,V> e; V oldValue;
            /**
             * 计算key的hash值
             */
            int hash = hash(key);
            /**
             * 找到对应的Node节点
             */
            if ((e = getNode(hash, key)) != null &&
                    (oldValue = e.value) != null) {
                //调用remappingFunction.apply获取新的value
                V v = remappingFunction.apply(key, oldValue);
                /**
                 * 如果新的value值不为空,就更新指定的node的value值
                 */
                if (v != null) {
                    e.value = v;
                    //啥也不做
                    afterNodeAccess(e);
                    //返回新的value
                    return v;
                }
                /**
                 * 如果新的value为空,就移除指定的node节点
                 */
                else
                    removeNode(hash, key, null, false, true);
            }
            return null;
        }

        /**
         * 通过key获取value,再通过remappingFunction.apply创建一个value,将这个value放进HashMap中并返回
         *
         * @param key
         * @param remappingFunction
         * @return
         */
        @Override
        public V compute(K key,
                         BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            if (remappingFunction == null)
                throw new NullPointerException();
            //计算key的hash值
            int hash = hash(key);
            Node<K,V>[] tab; Node<K,V> first; int n, i;
            int binCount = 0;
            TreeNode<K,V> t = null;
            Node<K,V> old = null;
            /**
             * 如果满足扩容条件,就扩容
             */
            if (size > threshold || (tab = table) == null ||
                    (n = tab.length) == 0)
                n = (tab = resize()).length;
            /**
             * 获取对应索引下的node节点
             */
            if ((first = tab[i = (n - 1) & hash]) != null) {
                /**
                 * 如果是红黑树节点,就调用getTreeNode查找对应节点
                 */
                if (first instanceof TreeNode)
                    old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
                /**
                 * 如果是链表,就循环查找
                 */
                else {
                    Node<K,V> e = first; K k;
                    do {
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k)))) {
                            old = e;
                            break;
                        }
                        ++binCount;
                    } while ((e = e.next) != null);
                }
            }
            /**
             * 获取查询到的value
             */
            V oldValue = (old == null) ? null : old.value;
            /**
             * 调用remappingFunction.apply获取一个新的value
             */
            V v = remappingFunction.apply(key, oldValue);
            /**
             * 如果查询的value不为空,新的value也不为空,就更新旧的value
             */
            if (old != null) {
                if (v != null) {
                    old.value = v;
                    //啥也不做
                    afterNodeAccess(old);
                }
                /**
                 * 如果新的value为空,就移除对应的node
                 */
                else
                    removeNode(hash, key, null, false, true);
            }
            /**
             * 如果查询到的value为空,并且新的value不为空的话
             */
            else if (v != null) {
                /**
                 * 如果第一个节点是红黑树的话,就通过putTreeVal添加一个节点
                 */
                if (t != null)
                    t.putTreeVal(this, tab, hash, key, v);
                /**
                 * 如果第一个节点是链表的话,就添加一个节点
                 */
                else {
                    tab[i] = newNode(hash, key, v, first);
                    /**
                     * 满足转换红黑树条件的话,就转换成红黑树
                     */
                    if (binCount >= TREEIFY_THRESHOLD - 1)
                        treeifyBin(tab, hash);
                }
                //记录修改的次数
                ++modCount;
                //size自增
                ++size;
                //啥也不做
                afterNodeInsertion(true);
            }
            //返回新的value
            return v;
        }


        /**
         *
         * @param key
         * @param value
         * @param remappingFunction
         * @return
         */
        @Override
        public V merge(K key, V value,
                       BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            if (value == null)
                throw new NullPointerException();
            if (remappingFunction == null)
                throw new NullPointerException();
            /**
             * 计算key的hash值
             */
            int hash = hash(key);
            Node<K,V>[] tab; Node<K,V> first; int n, i;
            int binCount = 0;
            TreeNode<K,V> t = null;
            Node<K,V> old = null;
            /**
             * 满足扩容条件就扩容
             */
            if (size > threshold || (tab = table) == null ||
                    (n = tab.length) == 0)
                n = (tab = resize()).length;
            /**
             * 拿到对应索引下的Node节点
             */
            if ((first = tab[i = (n - 1) & hash]) != null) {
                /**
                 * 如果是红黑树节点,就调用对应的getTreeNode查询节点
                 */
                if (first instanceof TreeNode)
                    old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
                /**
                 * 如果是链表,就循环查询
                 */
                else {
                    Node<K,V> e = first; K k;
                    do {
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k)))) {
                            old = e;
                            break;
                        }
                        ++binCount;
                    } while ((e = e.next) != null);
                }
            }
            /**
             * 如果查询到的节点不为空
             */
            if (old != null) {
                V v;
                //如果节点的value不为空,就remappingFunction.apply获得一个新的value
                if (old.value != null)
                    v = remappingFunction.apply(old.value, value);
                //如果节点的value为空,就把value给到新的value
                else
                    v = value;
                //如果新的value不为空,就更新节点的value
                if (v != null) {
                    old.value = v;
                    //啥也不做
                    afterNodeAccess(old);
                }
                //如果新的value为空,就删除节点
                else
                    removeNode(hash, key, null, false, true);
                //返回新的value
                return v;
            }
            /**
             * 如果查询不到节点,并且给的value不为空
             */
            if (value != null) {
                //如果第一个节点是红黑树节点,调用putTreeVal添加进红黑树
                if (t != null)
                    t.putTreeVal(this, tab, hash, key, value);
                //如果第一个节点是链表,就添加进链表
                else {
                    tab[i] = newNode(hash, key, value, first);
                    //如果满足转换红黑树的条件,就转换红黑树
                    if (binCount >= TREEIFY_THRESHOLD - 1)
                        treeifyBin(tab, hash);
                }
                //记录修改次数
                ++modCount;
                //size自增
                ++size;
                //啥也不做
                afterNodeInsertion(true);
            }
            //返回value
            return value;
        }

        /**
         * 遍历键值对
         * @param action
         */
        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            Node<K,V>[] tab;
            if (action == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                //记录遍历前modCount
                int mc = modCount;
                //双重循环遍历
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
                        action.accept(e.key, e.value);
                }
                //对比前后的modCount,判断是否被其他线程修改
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }

        /**
         *
         * @param function
         */
        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            Node<K,V>[] tab;
            if (function == null)
                throw new NullPointerException();
            if (size > 0 && (tab = table) != null) {
                //记录遍历前modCount
                int mc = modCount;
                //双重循环遍历,更新所有的value值
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                        e.value = function.apply(e.key, e.value);
                    }
                }
                //对比前后的modCount,判断是否被其他线程修改
                if (modCount != mc)
                    throw new ConcurrentModificationException();
            }
        }

        /**
         * 实现clone方法。(浅拷贝)
         * @return
         */
        @SuppressWarnings("unchecked")
        @Override
        public Object clone() {
            HashMap<K,V> result;
            try {
                result = (HashMap<K,V>)super.clone();
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError(e);
            }
            result.reinitialize();
            result.putMapEntries(this, false);
            return result;
        }

        /**
         * 加载因子
         * @return
         */
        final float loadFactor() { return loadFactor; }

        /**
         * 容量
         * @return
         */
        final int capacity() {
            return (table != null) ? table.length :
                    (threshold > 0) ? threshold :
                            DEFAULT_INITIAL_CAPACITY;
        }

        /**
         * 用于序列化调用
         * @param s
         * @throws IOException
         */
        private void writeObject(java.io.ObjectOutputStream s)
                throws IOException {
            int buckets = capacity();
            // Write out the threshold, loadfactor, and any hidden stuff
            s.defaultWriteObject();
            s.writeInt(buckets);
            s.writeInt(size);
            internalWriteEntries(s);
        }

        /**
         * 用于反序列化调用
         * @param s
         * @throws IOException
         * @throws ClassNotFoundException
         */
        private void readObject(java.io.ObjectInputStream s)
                throws IOException, ClassNotFoundException {
            // 读取反序列化数据
            s.defaultReadObject();
            reinitialize();
            if (loadFactor <= 0 || Float.isNaN(loadFactor))
                throw new InvalidObjectException("Illegal load factor: " +
                        loadFactor);
            s.readInt();                // Read and ignore number of buckets
            int mappings = s.readInt(); // Read number of mappings (size)
            if (mappings < 0)
                throw new InvalidObjectException("Illegal mappings count: " +
                        mappings);
            else if (mappings > 0) {
                /**
                 * 下面都是计算新的HashMap的容量和扩容阀值
                 */
                float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
                float fc = (float)mappings / lf + 1.0f;
                int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                        DEFAULT_INITIAL_CAPACITY :
                        (fc >= MAXIMUM_CAPACITY) ?
                                MAXIMUM_CAPACITY :
                                tableSizeFor((int)fc));
                float ft = (float)cap * lf;
                threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
                        (int)ft : Integer.MAX_VALUE);
                /**
                 * 创建一个新的数组
                 */
                @SuppressWarnings({"rawtypes","unchecked"})
                Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
                table = tab;

                // 循环读取key和value,并设置进数组
                for (int i = 0; i < mappings; i++) {
                    @SuppressWarnings("unchecked")
                    K key = (K) s.readObject();
                    @SuppressWarnings("unchecked")
                    V value = (V) s.readObject();
                    putVal(hash(key), key, value, false, false);
                }
            }
        }


        /**
         * 迭代器
         */
        abstract class HashIterator {
            /**
             * 下一个节点
             */
            Node<K,V> next;        // next entry to return
            /**
             * 当前节点
             */
            Node<K,V> current;     // current entry
            /**
             * 记录被修改次数,防止迭代的时候数据发生变化
             */
            int expectedModCount;  // for fast-fail
            /**
             * 当前的索引值
             */
            int index;             // current slot

            /**
             * 构造函数
             */
            HashIterator() {
                expectedModCount = modCount;
                Node<K,V>[] t = table;
                current = next = null;
                index = 0;
                /**
                 * 从索引0开始遍历,遍历到第一个不为空的Node
                 */
                if (t != null && size > 0) { // advance to first entry
                    do {} while (index < t.length && (next = t[index++]) == null);
                }
            }

            /**
             * 判断是否有下一个节点
             * @return
             */
            public final boolean hasNext() {
                return next != null;
            }

            /**
             * 获取下一个节点
             * @return
             */
            final Node<K,V> nextNode() {
                Node<K,V>[] t;
                Node<K,V> e = next;
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                if (e == null)
                    throw new NoSuchElementException();
                /**
                 * 遍历判断next!=null
                 */
                if ((next = (current = e).next) == null && (t = table) != null) {
                    do {} while (index < t.length && (next = t[index++]) == null);
                }
                return e;
            }

            /**
             * 移除当前节点
             */
            public final void remove() {
                Node<K,V> p = current;
                if (p == null)
                    throw new IllegalStateException();
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                current = null;
                K key = p.key;
                /**
                 * 根据当前节点的key移除
                 */
                removeNode(hash(key), key, null, false, false);
                expectedModCount = modCount;
            }
        }

        /**
         * 针对key的迭代器
         */
        final class KeyIterator extends HashIterator
                implements Iterator<K> {
            public final K next() { return nextNode().key; }
        }

        /**
         * 针对value的迭代器
         */
        final class ValueIterator extends HashIterator
                implements Iterator<V> {
            public final V next() { return nextNode().value; }
        }

        /**
         * 针对键值对的迭代器
         */
        final class EntryIterator extends HashIterator
                implements Iterator<Map.Entry<K,V>> {
            public final Map.Entry<K,V> next() { return nextNode(); }
        }

因文章篇幅问题,后面的源码分析无法发布。不过上述分析已经将HashMap的基本原理讲述明白。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348