精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

HashMap源碼分析,看一遍就懂!

開發 后端
HashMap最早出現在JDK1.2中,底層基于散列算法實現。HashMap 允許 null 鍵和 null 值,是非線程安全類,在多線程環境下可能會存在問題。

簡介

HashMap最早出現在JDK1.2中,底層基于散列算法實現。HashMap 允許 null 鍵和 null 值,是非線程安全類,在多線程環境下可能會存在問題。

1.8版本的HashMap數據結構:

為什么有的是鏈表有的是紅黑樹?

默認鏈表長度大于8時轉為樹。

結構

Node是HhaspMap中的一個靜態內部類 :

//Node是單向鏈表,實現了Map.Entry接口
static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
    //構造函數
    Node(int hash, K key, V value, Node<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }

    // getter and setter ... toString ...
    public final K getKey()        { return key; }
    public final V getValue()      { return value; }
    public final String toString() { return key + "=" + value; }

    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }

    public final V setValue(V newValue) {
        V oldValue = value;
        value = newValue;
        return oldValue;
    }

    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;
    }
}

TreeNode 是紅黑樹的數據結構。

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    TreeNode<K,V> parent;  // red-black tree links
    TreeNode<K,V> left;
    TreeNode<K,V> right;
    TreeNode<K,V> prev;    // needed to unlink next upon deletion
    boolean red;
    TreeNode(int hash, K key, V val, Node<K,V> next) {
        super(hash, key, val, next);
    }

    /**
     * Returns root of tree containing this node.
     */
    final TreeNode<K,V> root() {
        for (TreeNode<K,V> r = this, p;;) {
            if ((p = r.parent) == null)
                return r;
            r = p;
        }
    }

類定義

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

變量

/**
 * 默認初始容量16(必須是2的冪次方)
 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

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

/**
 * 默認加載因子,用來計算threshold
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
 * 鏈表轉成樹的閾值,當桶中鏈表長度大于8時轉成樹 
   threshold = capacity * loadFactor
 */
static final int TREEIFY_THRESHOLD = 8;

/**
 * 進行resize操作時,若桶中數量少于6則從樹轉成鏈表
 */
static final int UNTREEIFY_THRESHOLD = 6;

/**
 * 桶中結構轉化為紅黑樹對應的table的最小大小

 當需要將解決 hash 沖突的鏈表轉變為紅黑樹時,
 需要判斷下此時數組容量,
 若是由于數組容量太小(小于 MIN_TREEIFY_CAPACITY )
 導致的 hash 沖突太多,則不進行鏈表轉變為紅黑樹操作,
 轉為利用 resize() 函數對 hashMap 擴容
 */
static final int MIN_TREEIFY_CAPACITY = 64;
/**
 保存Node<K,V>節點的數組
 該表在首次使用時初始化,并根據需要調整大小。 分配時,
 長度始終是2的冪。
 */
transient Node<K,V>[] table;

/**
 * 存放具體元素的集
 */
transient Set<Map.Entry<K,V>> entrySet;

/**
 * 記錄 hashMap 當前存儲的元素的數量
 */
transient int size;

/**
 * 每次更改map結構的計數器
 */
transient int modCount;

/**
 * 臨界值 當實際大小(容量*填充因子)超過臨界值時,會進行擴容
 */
int threshold;

/**
 * 負載因子:要調整大小的下一個大小值(容量*加載因子)。
 */
final float loadFactor;

構造方法

/**
 * 傳入初始容量大小,使用默認負載因子值 來初始化HashMap對象
 */
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

/**
 * 默認容量和負載因子
 */
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
/**
 * 傳入初始容量大小和負載因子 來初始化HashMap對象
 */
public HashMap(int initialCapacity, float loadFactor) {
    // 初始容量不能小于0,否則報錯
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    // 初始容量不能大于最大值,否則為最大值                                       
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    //負載因子不能小于或等于0,不能為非數字    
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);
    // 初始化負載因子                                       
    this.loadFactor = loadFactor;
    // 初始化threshold大小
    this.threshold = tableSizeFor(initialCapacity);
}

/**
 * 找到大于或等于 cap 的最小2的整數次冪的數。
 */
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;
}

tableSizeFor方法詳解:

用位運算找到大于或等于 cap 的最小2的整數次冪的數。比如10,則返回16

  • 讓cap-1再賦值給n的目的是使得找到的目標值大于或等于原值。例如二進制0100,十進制是4,若不減1而直接操作,答案是0001 0000十進制是16,明顯不符合預期。
  • 對n右移1位:001xx…xxx,再位或:011xx…xxx
  • 對n右移2位:00011…xxx,再位或:01111…xxx
  • 對n右移4位…
  • 對n右移8位…
  • 對n右移16位,因為int最大就2^32所以移動1、2、4、8、16位并取位或,會將最高位的1后面的位全變為1。
  • 再讓結果n+1,即得到了2的整數次冪的值了。

附帶一個實例:

loadFactor 負載因子

對于 HashMap 來說,負載因子是一個很重要的參數,該參數反應了 HashMap 桶數組的使用情況。通過調節負載因子,可使 HashMap 時間和空間復雜度上有不同的表現。

當我們調低負載因子時,HashMap 所能容納的鍵值對數量變少。擴容時,重新將鍵值對存儲新的桶數組里,鍵的鍵之間產生的碰撞會下降,鏈表長度變短。此時,HashMap 的增刪改查等操作的效率將會變高,這里是典型的拿空間換時間。相反,如果增加負載因子(負載因子可以大于1),HashMap 所能容納的鍵值對數量變多,空間利用率高,但碰撞率也高。這意味著鏈表長度變長,效率也隨之降低,這種情況是拿時間換空間。至于負載因子怎么調節,這個看使用場景了。

一般情況下,我們用默認值就可以了。大多數情況下0.75在時間跟空間代價上達到了平衡所以不建議修改。

查找

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}
// 獲取hash值
static final int hash(Object key) {
    int h;
    // 拿到key的hash值后與其五符號右移16位取與
    // 通過這種方式,讓高位數據與低位數據進行異或,以此加大低位信息的隨機性,變相的讓高位數據參與到計算中。
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; 
    Node<K,V> first, e; 
    int n; K k;
    // 定位鍵值對所在桶的位置
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        // 判斷桶中第一項(數組元素)相等
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        // 桶中不止一個結點
        if ((e = first.next) != null) {
            // 是否是紅黑樹,是的話調用getTreeNode方法
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            // 不是紅黑樹的話,在鏈表中遍歷查找    
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

注意:

  • HashMap的hash算法(hash()方法)。
  • (n - 1) & hash等價于對 length 取余。

添加

public V put(K key, V value) {
    // 調用hash(key)方法來計算hash 
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; 
    Node<K,V> p; 
    int n, i;
    // 容量初始化:當table為空,則調用resize()方法來初始化容器
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    //確定元素存放在哪個桶中,桶為空,新生成結點放入桶中
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        // 比較桶中第一個元素(數組中的結點)的hash值相等,key相等
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            //如果鍵的值以及節點 hash 等于鏈表中的第一個鍵值對節點時,則將 e 指向該鍵值對
            e = p;
        // 如果桶中的引用類型為 TreeNode,則調用紅黑樹的插入方法
        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);
                    // 如果結點數量達到閾值,轉化為紅黑樹
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                // 判斷鏈表中結點的key值與插入的元素的key值是否相等
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        //判斷要插入的鍵值對是否存在 HashMap 中
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            // onlyIfAbsent 表示是否僅在 oldValue 為 null 的情況下更新鍵值對的值
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    // 鍵值對數量超過閾值時,則進行擴容
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

事實上,new HashMap();完成后,如果沒有put操作,是不會分配存儲空間的。

  • 當桶數組 table 為空時,通過擴容的方式初始化 table。
  • 查找要插入的鍵值對是否已經存在,存在的話根據條件判斷是否用新值替換舊值。
  • 如果不存在,則將鍵值對鏈入鏈表中,并根據鏈表長度決定是否將鏈表轉為紅黑樹。
  • 判斷鍵值對數量是否大于閾值,大于的話則進行擴容操作。

擴容機制

在 HashMap 中,桶數組的長度均是2的冪,閾值大小為桶數組長度與負載因子的乘積。當 HashMap 中的鍵值對數量超過閾值時,進行擴容。

HashMap 按當前桶數組長度的2倍進行擴容,閾值也變為原來的2倍(如果計算過程中,閾值溢出歸零,則按閾值公式重新計算)。擴容之后,要重新計算鍵值對的位置,并把它們移動到合適的位置上去。

final Node<K,V>[] resize() {
    // 拿到數組桶
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    // 如果數組桶的容量大與0
    if (oldCap > 0) {
        // 如果比最大值還大,則賦值為最大值
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        // 如果擴容后小于最大值 而且 舊數組桶大于初始容量16, 閾值左移1(擴大2倍)
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold
    }
    // 如果數組桶容量<=0 且 舊閾值 >0
    else if (oldThr > 0) // initial capacity was placed in threshold
        // 新容量=舊閾值
        newCap = oldThr;
    // 如果數組桶容量<=0 且 舊閾值 <=0
    else {               // zero initial threshold signifies using defaults
        // 新容量=默認容量
        newCap = DEFAULT_INITIAL_CAPACITY;
        // 新閾值= 負載因子*默認容量
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    // 如果新閾值為0
    if (newThr == 0) {
        // 重新計算閾值
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    // 更新閾值
    threshold = newThr;
    @SuppressWarnings({"rawtypes","unchecked"})
        // 創建新數組
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    // 覆蓋數組桶    
    table = newTab;
    // 如果舊數組桶不是空,則遍歷桶數組,并將鍵值對映射到新的桶數組中
    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
                oldTab[j] = null;
                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;
}

整體步驟:

  • 計算新桶數組的容量 newCap 和新閾值 newThr
  • 根據計算出的 newCap 創建新的桶數組,桶數組 table 也是在這里進行初始化的
  • 將鍵值對節點重新映射到新的桶數組里。如果節點是 TreeNode 類型,則需要拆分紅黑樹。如果是普通節點,則節點按原順序進行分組。

總結起來,一共有三種擴容方式:

  • 使用默認構造方法初始化HashMap。從前文可以知道HashMap在一開始初始化的時候會返回一個空的table,并且thershold為0。因此第一次擴容的容量為默認值DEFAULT_INITIAL_CAPACITY也就是16。同時threshold = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR = 12。
  • 指定初始容量的構造方法初始化HashMap。那么從下面源碼可以看到初始容量會等于threshold,接著threshold = 當前的容量(threshold) * DEFAULT_LOAD_FACTOR。
  • HashMap不是第一次擴容。如果HashMap已經擴容過的話,那么每次table的容量以及threshold量為原有的兩倍。

細心點的人會很好奇,為什么要判斷loadFactor為0呢?

loadFactor小數位為 0,整數位可被2整除且大于等于8時,在某次計算中就可能會導致 newThr 溢出歸零。

疑問和進階

1、JDK1.7是基于數組+單鏈表實現(為什么不用雙鏈表)

首先,用鏈表是為了解決hash沖突。

單鏈表能實現為什么要用雙鏈表呢?(雙鏈表需要更大的存儲空間)

2、為什么要用紅黑樹,而不用平衡二叉樹?

插入效率比平衡二叉樹高,查詢效率比普通二叉樹高。所以選擇性能相對折中的紅黑樹。

3、重寫對象的Equals方法時,要重寫hashCode方法,為什么?跟HashMap有什么關系?

equals與hashcode間的關系:

  • 如果兩個對象相同(即用equals比較返回true),那么它們的hashCode值一定要相同。
  • 如果兩個對象的hashCode相同,它們并不一定相同(即用equals比較返回false)。

因為在 HashMap 的鏈表結構中遍歷判斷的時候,特定情況下重寫的 equals 方法比較對象是否相等的業務邏輯比較復雜,循環下來更是影響查找效率。所以這里把 hashcode 的判斷放在前面,只要 hashcode 不相等就玩兒完,不用再去調用復雜的 equals 了。很多程度地提升 HashMap 的使用效率。

所以重寫 hashcode 方法是為了讓我們能夠正常使用 HashMap 等集合類,因為 HashMap 判斷對象是否相等既要比較 hashcode 又要使用 equals 比較。而這樣的實現是為了提高 HashMap 的效率。

附上源碼圖:

4、HashMap為什么不直接使用對象的原始hash值呢?

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

我們發現,HashMap的哈希值是通過上面的方式獲取,而不是通過key.hashCode()方法獲取。

原因:

通過移位和異或運算,可以讓 hash 變得更復雜,進而影響 hash 的分布性。

5、既然紅黑樹那么好,為啥hashmap不直接采用紅黑樹,而是當大于8個的時候才轉換紅黑樹?

因為紅黑樹需要進行左旋,右旋操作, 而單鏈表不需要。

以下都是單鏈表與紅黑樹結構對比。

如果元素小于8個,查詢成本高,新增成本低。

如果元素大于8個,查詢成本低,新增成本高。

至于為什么選數字8,是大佬折中衡量的結果-.-,就像loadFactor默認值0.75一樣。

責任編輯:姜華 來源: 今日頭條
相關推薦

2021-08-12 10:36:18

order byMySQL數據庫

2021-10-08 07:53:01

事務隔離級別

2021-06-15 07:15:15

Oracle底層explain

2022-01-17 20:59:37

開發group by思路

2025-02-13 09:06:27

2021-12-01 07:26:13

IO模型異步

2024-03-26 07:59:32

IO模型多路復用

2021-10-07 20:12:03

MVCC事務原理

2024-03-12 08:20:57

零拷貝存儲開發

2020-02-09 17:30:54

反轉鏈表程序員節點

2022-08-26 10:41:03

指針C語言

2022-05-08 23:05:38

Route-Poli路由策略

2019-09-19 08:04:40

網絡七層模型TCPUDP

2019-03-19 14:11:44

VLANLANMAC

2023-08-14 07:49:42

AI訓練

2020-06-17 09:52:16

數據庫Redis技術

2023-01-10 19:47:47

Redis原理多線程

2017-12-26 14:17:24

潤乾報表

2024-05-21 08:40:21

分庫分表源碼

2021-11-25 08:16:46

Wi-FiWi-Fi 6路由Wi-Fi 5
點贊
收藏

51CTO技術棧公眾號

9.1片黄在线观看| 人妻熟女一二三区夜夜爱| 国产精品久久777777换脸| 亚洲国产一区二区三区在线播放| 日韩一区二区在线免费观看| 阿v天堂2018| 成人在线视频成人| 国产成人久久精品77777最新版本| 57pao成人永久免费视频| 综合 欧美 亚洲日本| 成人av激情人伦小说| 欧美四级电影在线观看| 久无码久无码av无码| 91这里只有精品| 成人福利在线看| 成人高h视频在线| 国产精品久免费的黄网站| 欧美国产日本| 综合136福利视频在线| 天堂www中文在线资源| 黄色日韩网站| 色天天综合色天天久久| 免费无码毛片一区二三区| 黄色一级大片在线免费看产| 久久久亚洲高清| 国产乱码精品一区二区三区卡| 一区二区三区www污污污网站| 亚洲欧美卡通另类91av| 欧美精品福利视频| 91视频综合网| 亚洲草久电影| 日韩亚洲第一页| 人妻精品久久久久中文| 丝袜美腿一区二区三区动态图| 欧美不卡一二三| 国产5g成人5g天天爽| 欧美性aaa| 欧美日韩一区视频| 日本 片 成人 在线| 欧美精选视频一区二区| 日本乱人伦aⅴ精品| 免费高清在线观看免费| 一区二区三区短视频| 天天色天天爱天天射综合| 国产一区二区三区小说| 肉肉视频在线观看| 亚洲欧美另类小说| 亚洲精品天堂成人片av在线播放| 高h视频在线观看| 亚洲欧美怡红院| 国产福利片一区二区| 色影视在线观看| 国产精品久久久久婷婷| 一区二区精品在线| caoporn97在线视频| 亚洲精品日产精品乱码不卡| 性生活免费观看视频| 91极品在线| 五月婷婷欧美视频| 欧美牲交a欧美牲交| 美女一区网站| 欧美日韩午夜精品| 中文字幕色网站| 久久久久久久久成人| 精品免费视频.| 日本护士做爰视频| 欧美猛男男男激情videos| 一个人www欧美| 国产suv精品一区二区68| 欧美高清不卡| 热re99久久精品国产66热| 国产精品第六页| 韩国v欧美v亚洲v日本v| 成人免费视频观看视频| 色天堂在线视频| 中文字幕乱码久久午夜不卡| 欧美三级午夜理伦三级老人| 超级白嫩亚洲国产第一| 色综合天天综合网国产成人综合天 | 欧美**字幕| 中文字幕亚洲欧美一区二区三区| 成人高潮免费视频| 国产精品99免费看| 日本高清+成人网在线观看| 中文字幕无码乱码人妻日韩精品| 麻豆国产精品一区二区三区 | 国产又大又黄又粗又爽| 999色成人| 亚洲国产另类 国产精品国产免费| 性欧美成人播放77777| 日韩激情免费| 欧美国产在线视频| 欧美激情一区二区三区免费观看| 极品少妇一区二区| 狠狠色狠狠色综合人人| 天天影视久久综合| 午夜久久久久久| 视频在线观看免费高清| 欧美绝顶高潮抽搐喷水合集| 社区色欧美激情 | 九九九国产视频| 久久99最新地址| 开心色怡人综合网站| 国产成人在线视频免费观看| 欧美日韩在线另类| 国产xxxxhd| 精品freesex老太交| 欧美黄色片在线观看| 伊人网av在线| 91亚洲男人天堂| 日本三级中文字幕在线观看| 在线观看精品| 亚洲精品久久久久中文字幕二区 | 午夜日韩在线电影| jizz18女人| 在线看成人短视频| 久久久久久综合网天天| 国产麻豆精品一区| 国产精品视频yy9299一区| 能在线观看的av| 最新国产精品精品视频| 操日韩av在线电影| 亚洲图片小说视频| 日本一区二区免费在线观看视频| 男人天堂1024| 卡一精品卡二卡三网站乱码| 伦伦影院午夜日韩欧美限制| 夜夜嗨av禁果av粉嫩avhd| 久久久精品黄色| 日韩欧美视频网站| 另类在线视频| 2019中文字幕在线免费观看| 刘亦菲久久免费一区二区| 亚洲免费看黄网站| 天堂在线精品视频| 亚洲精品99| 92看片淫黄大片欧美看国产片 | 久久人人爽人人| 亚洲精品久久久久avwww潮水| ●精品国产综合乱码久久久久| 国产一级不卡毛片| japanese国产精品| 国产精品视频一区二区三区四 | 欧美激情视频免费观看| 国产suv一区二区| 亚洲精品免费在线| 337p日本欧洲亚洲大胆张筱雨 | 亚洲精品综合在线观看| 欧美mv日韩| 91久久久久久久久久久久久| 国内精品久久久久久野外| 欧美一二三在线| 久久国产露脸精品国产| 国产不卡视频一区二区三区| 激情五月婷婷六月| 欧美美女啪啪| 国产精品wwww| 欧美jizz18性欧美| 欧美大胆一级视频| 国产精品23p| 久久久久久99精品| 91极品尤物在线播放国产| 99久久亚洲精品蜜臀| 91沈先生在线观看| 久草免费在线色站| 亚洲欧美国产精品久久久久久久| 亚洲va在线观看| 国产精品久久久久久久午夜片| 激情在线观看视频| 在线电影一区| 日韩电影大全在线观看| 国产成年精品| 欧美精品福利视频| 国产福利在线看| 日韩一卡二卡三卡国产欧美| 国产成人亚洲精品自产在线| 久久久精品日韩欧美| 在线免费黄色网| 亚洲国产免费看| 日韩av电影免费在线观看| 亚洲影视资源| 91地址最新发布| 欧美一级二级三级区| 亚洲国产小视频在线观看| 日韩国产亚洲欧美| 一区二区三区视频在线看| 国产又粗又猛又色| 久久超级碰视频| 玩弄中年熟妇正在播放| 久久综合88| 麻豆久久久9性大片| 未满十八勿进黄网站一区不卡| 久久久久久久久爱| av网站无病毒在线| 日韩精品影音先锋| 欧美激情一区二区三区免费观看| 亚洲一本大道在线| 日本爱爱小视频| 久久伊99综合婷婷久久伊| 91精品视频国产| 日韩成人免费在线| 欧美精品自拍视频| 亚洲自拍偷拍网| 视频一区二区三| 欧美日韩破处| 51午夜精品| 婷婷精品久久久久久久久久不卡| 国产91精品久| 丁香花在线电影小说观看| 久久精品国产成人| 国产三级在线| 精品亚洲va在线va天堂资源站| 99国产精品99| 欧美日韩国产天堂| 无码人妻精品一区二区三区蜜桃91| 亚洲午夜一二三区视频| 午夜爽爽爽男女免费观看| 国产视频在线观看一区二区三区 | 亚洲精品一二三四五区| 国产欧美91| 久久久久久久久久网| 欧美日韩国产高清| 久久久国产精华液999999| 成人精品影视| 日韩三级电影网站| 欧美精选一区二区三区| 久久亚洲午夜电影| 老牛精品亚洲成av人片| 国产精品xxx在线观看www| 久久久91麻豆精品国产一区| 91久久精品国产| 一区二区三区无毛| 成人看片人aa| 高清一区二区三区av| 国产在线高清精品| 久久久久久久性潮| 国产日韩在线亚洲字幕中文| 欧美大片1688网站| 国产剧情日韩欧美| 国外成人福利视频| 成人精品福利视频| 国产精品日本一区二区不卡视频| 成人福利在线视频| 欧州一区二区三区| 99视频日韩| 成人在线视频你懂的| 国产亚洲欧美另类一区二区三区| 开心激情综合| 欧美精品123| 日韩精品一区二区三区免费观影 | 狠狠色狠狠色综合人人| 奇米影视777在线欧美电影观看| 国产综合av一区二区三区| 任你弄精品视频免费观看| 久久久精品国产一区二区三区| 一区二区三区视频免费观看| 欧美日韩一区二区三| 欧美色女视频| 精品91一区二区三区| 欧美日韩一区自拍| 鲁一鲁一鲁一鲁一澡| 玖玖国产精品视频| 五月婷婷之婷婷| 国产精品资源在线观看| 午夜视频在线观看国产| 久久久国产一区二区三区四区小说 | 欧美福利视频在线| 国产va在线视频| 国产精品第一第二| 成人影院网站ww555久久精品| av成人午夜| 亚洲精品3区| 一区二区三区av在线| 国产精品v日韩精品v欧美精品网站| 国产二区视频在线| 日韩电影在线观看一区| 在线播放国产视频| 久久综合狠狠综合久久激情| 国产美女网站视频| 亚洲午夜影视影院在线观看| 99re国产在线| 日韩视频在线观看一区二区| 亚洲 欧美 自拍偷拍| 日韩在线视频网| gogo久久| 成人亚洲激情网| 日韩精品社区| 超碰在线免费观看97| 在线视频免费在线观看一区二区| 污污网站免费观看| 91麻豆精品一区二区三区| 国产美女久久久久久| 狠狠躁天天躁日日躁欧美| 国产理论视频在线观看| 精品视频久久久久久| 最新黄网在线观看| 国产成人黄色av| 风间由美性色一区二区三区四区 | 91大神在线网站| 国外成人免费在线播放 | 久久久久久久久久久久久久一区 | 久久精品国产亚洲5555| 亚洲国产成人不卡| 国产精品毛片在线| 青娱乐精品在线| 欧美国产成人在线| 日韩精品久久久久久久| 5月丁香婷婷综合| 欧美亚洲日本| 国模精品视频一区二区| 视频一区中文字幕精品| 亚洲精品国产精品国自产观看| 99riav1国产精品视频| 特黄特黄一级片| 国产精品美女久久久久av爽李琼| 国产精品久久久久久99| 欧美一二三区在线| 午夜视频在线看| 国产精品成av人在线视午夜片 | 国产视频在线观看一区二区| 免费影视亚洲| 亚洲精品欧美日韩| 久久精品久久久| 久热在线视频观看| 国产精品网站一区| 国产真人无遮挡作爱免费视频| 日韩av网站在线| caoporn视频在线| 国产高清在线一区| 午夜精品久久99蜜桃的功能介绍| www.51色.com| 亚洲三级小视频| 国产免费黄色录像| 久久夜色精品国产亚洲aⅴ| 欧洲美女精品免费观看视频 | 国产免费高清一区| 影音先锋久久| 日本不卡视频一区| 亚洲高清视频在线| 欧美一区二区三区黄片| 97高清免费视频| 偷拍视屏一区| 北条麻妃av高潮尖叫在线观看| 国产亚洲一二三区| 国产一级精品毛片| 色悠悠久久久久| 精品视频成人| www..com日韩| 久久综合五月天婷婷伊人| 精品人妻无码一区二区性色| 亚洲天堂av电影| 日韩三区四区| 伊人网在线免费| 成人免费毛片app| 国产又大又黄视频| 国产亚洲精品91在线| 国内精品伊人| 日产精品久久久久久久蜜臀| 成人午夜av电影| 国产嫩bbwbbw高潮| 日韩中文字幕精品| 视频精品国内| 人妻熟妇乱又伦精品视频| 欧美国产禁国产网站cc| 一级全黄裸体免费视频| 欧美成人免费网| 久久久久影视| 黄色三级视频片| 亚洲精品欧美在线| 色视频在线观看免费| 国产精品69av| 欧美日韩亚洲一区在线观看| 国产人妻人伦精品1国产丝袜| 欧美日韩在线电影| 激情影院在线| 日本一区二区三区视频在线观看| 久热成人在线视频| 国产无遮挡aaa片爽爽| 亚洲图中文字幕| 天堂精品久久久久| 777米奇影视第四色| 亚洲少妇中出一区| 亚洲av片在线观看| 成人国产精品久久久| 99国产精品自拍| 国产免费一区二区三区四区| 精品国产91乱码一区二区三区| 欧美www.| 青青在线免费观看| 国产精品久久久久久久久搜平片| 亚洲va欧美va| 国产精品美女无圣光视频| 激情久久综合| 婷婷社区五月天| 亚洲美女激情视频| 一区二区三区在线资源| 国产aaaaa毛片| 精品久久久久久国产91| 中文字幕中文字幕在线中高清免费版| 久久久久久国产精品mv|