久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術文章
文章詳情頁

深入理解Java中的HashMap

瀏覽:97日期:2022-08-10 18:43:04
目錄一、HashMap的結構圖示二、HashMap的成員變量以及含義2.1、hash方法說明2.2、tableSizeFor方法說明三、HashMap的構造方法四、HashMap元素在數組中的位置五、HashMap的put方法分析5.1、put方法源碼分析5.2、put方法執行過程總結六、HashMap的resize方法分析6.1、resize方法源碼6.2、(e.hash & oldCap) == 0分析6.3、部分代碼理解6.4、resize總結七、HashMap的get方法分析7.1、get方法源碼一、HashMap的結構圖示

​本文主要說的是jdk1.8版本中的實現。而1.8中HashMap是數組+鏈表+紅黑樹實現的,大概如下圖所示。后面還是主要介紹Hash Map中主要的一些成員以及方法原理。

深入理解Java中的HashMap

​那么上述圖示中的結點Node具體類型是什么,源碼如下。Node是HashMap的內部類,實現了Map.Entery接口,主要就是存放我們put方法所添加的元素。其中的next就表示這可以構成一個單向鏈表,這主要是通過鏈地址法解決發生hash沖突問題。而當桶中的元素個數超過閾值的時候就換轉為紅黑樹。

//hash桶中的結點Node,實現了Map.Entrystatic class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; //鏈表的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; } //重寫Object的hashCode public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value); } public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue; } //equals方法 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; }}//轉變為紅黑樹后的結點類static final class TreeNode<k,v> extends LinkedHashMap.Entry<k,v> { TreeNode<k,v> parent; // 父節點 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); } //返回當前節點的根節點 final TreeNode<k,v> root() {for (TreeNode<k,v> r = this, p;;) { if ((p = r.parent) == null)return r; r = p;} }}

​上面只是大概了解了一下HashMap的簡單組成,下面主要介紹其中的一些參數和重要的方法原理實現。

二、HashMap的成員變量以及含義

//默認初始化容量初始化=16static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16//最大容量 = 1 << 30static final int MAXIMUM_CAPACITY = 1 << 30;//默認加載因子.一般HashMap的擴容的臨界點是當前HashMap的大小 > DEFAULT_LOAD_FACTOR * //DEFAULT_INITIAL_CAPACITY = 0.75F * 16static final float DEFAULT_LOAD_FACTOR = 0.75f;//當hash桶中的某個bucket上的結點數大于該值的時候,會由鏈表轉換為紅黑樹static final int TREEIFY_THRESHOLD = 8;//當hash桶中的某個bucket上的結點數小于該值的時候,紅黑樹轉變為鏈表static final int UNTREEIFY_THRESHOLD = 6;//桶中結構轉化為紅黑樹對應的table的最小大小static final int MIN_TREEIFY_CAPACITY = 64;//hash算法,計算傳入的key的hash值,下面會有例子說明這個計算的過程static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);} //tableSizeFor(initialCapacity)返回大于initialCapacity的最小的二次冪數值。下面會有例子說明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;}//hash桶transient Node<K,V>[] table;//保存緩存的entrySettransient Set<Map.Entry<K,V>> entrySet;//桶的實際元素個數 != table.lengthtransient int size;//擴容或者更改了map的計數器。含義:表示這個HashMap結構被修改的次數,結構修改是那些改變HashMap中的映射數量或者//修改其內部結構(例如,重新散列rehash)的修改。 該字段用于在HashMap失敗快速(fast-fail)的Collection-views//上創建迭代器。transient int modCount;//臨界值,當實際大小(cap*loadFactor)大于該值的時候,會進行擴充int threshold;//加載因子final float loadFactor;2.1、hash方法說明

//hash算法static final int hash(Object key) { int h; //key == null : 返回hash=0 //key != null //(1)得到key的hashCode:h=key.hashCode() //(2)將h無符號右移16位 //(3)異或運算:h ^ h>>>16 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}

​假設現在我們向一個map中添加元素,例如map.put('fsmly','test'),那么其中key為'fsmly'的hashCode的二進制表示為0000_0000_0011_0110_0100_0100_1001_0010,按照上面的步驟來計算,那么我們調用hash算法得到的hash值為:‭

深入理解Java中的HashMap

2.2、tableSizeFor方法說明

​該方法的作用就是:返回大于initialCapacity的最小的二次冪數值。如下實例

//n=cap-1=5; 5的二進制0101B。>>> 操作符表示無符號右移,高位取0//n |= n>>>1: (1)n=0101 | 0101>>>1; (2)n=0101 | 0010; (3)n = 0111B //n |= n>>>2: (1)n=0111 | 0111>>>2; (2)n=0111 | 0011; (3)n = 0111B//n |= n>>>4: (1)n=0111 | 0111>>>4; (2)n=0111 | 0000; (3)n = 0111B//n |= n>>>8: (1)n=0111 | 0111>>>8; (2)n=0111 | 0000; (3)n = 0111B//n |= n>>>16:(1)n=0111 | 0111>>>16;(2)n=0111 | 0000; (3)n = 0111Bstatic final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; //n<0返回1 //n>最大容量,返回最大容量 //否則返回n+1(0111B+1B=1000B=8) return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}

​再看下面這個:

//至于這里為什么減1,當傳入的cap為2的整數次冪的時候,減1即保證最后的計算結果還是cap,而不是大于cap的另一個2的//整數次冪,例如我們傳入cap=16=10000B.按照上面那樣計算//n=cap-1=15=1111B.按照上面的方法計算得到:// n |= n>>>1: n=1111|0111=1111;后面還是相同的結果最后n=1111B=15.//所以返回的時候為return 15+1;int n = cap - 1; 三、HashMap的構造方法

​我們看看HashMap源碼中為我們提供的四個構造方法。我們可以看到,平常我們最常用的無參構造器內部只是僅僅初始化了loadFactor,別的都沒有做,底層的數據結構則是延遲到插入鍵值對時再進行初始化,或者說在resize中會做。后面說到擴容方法的實現的時候會講到。

//(1)參數為初始化容量和加載因子的構造函數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; this.threshold = tableSizeFor(initialCapacity); //閾值為大于initialCapacity的最小二次冪}//(2)只給定初始化容量,那么加載因子就是默認的加載因子:0.75public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR);}//(3)加載因子為默認的加載因子,但是這個時候的初始化容量是沒有指定的,后面調用put或者get方法的時候才resizepublic HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}//(4)將傳遞的map中的值調用putMapEntries加入新的map集合中,其中加載因子是默認的加載因子public HashMap(Map<? extends K, ? extends V> m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false);}四、HashMap元素在數組中的位置

​不管增加、刪除、查找鍵值對,定位到哈希桶數組的索引都是很關鍵的第一步,所以我們看看源碼怎樣通過hash()方法以及其他代碼確定一個元素在hash桶中的位置的。

//計算map中key的hash值static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}//這一小段代碼就是定位元素在桶中的位置。具體做法就是:容量n-1 & hash. //其中n是一個2的整數冪,而(n - 1) & hash其實質就是hash%n,但//是取余運算的效率不如位運算與,并且(n - 1) & hash也能保證散列均勻,不會產生只有偶數位有值的現象p = tab[i = (n - 1) & hash];

​下面我們通過一個例子計算一下上面這個定位的過程,假設現在桶大小n為16.

深入理解Java中的HashMap

​我們可以看到,這里的hash方法并不是用原有對象的hashcode最為最終的hash值,而是做了一定位運算,大概因為如果(n-1)的值太小的話,(n - 1) & hash的值就完全依靠hash的低位值,比如n-1為0000 1111,那么最終的值就完全依賴于hash值的低4位了,這樣的話hash的高位就玩完全失去了作用,h ^ (h >>> 16),通過這種方式,讓高位數據與低位數據進行異或,也是變相的加大了hash的隨機性,這樣就不單純的依賴對象的hashcode方法了。

五、HashMap的put方法分析5.1、put方法源碼分析

public V put(K key, V value) { 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 == null 或者table的長度為0,調用resize方法進行擴容 //這里也說明:table 被延遲到插入新數據時再進行初始化 if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length; // 這里就是調用了Hash算法的地方,具體的計算可參考后面寫到的例子 //這里定位坐標的做法在上面也已經說到過 if ((p = tab[i = (n - 1) & hash]) == null)// 如果計算得到的桶下標值中的Node為null,就新建一個Node加入該位置(這個新的結點是在//table數組中)。而該位置的hash值就是調用hash()方法計算得到的key的hash值tab[i] = newNode(hash, key, value, null); //這里表示put的元素用自己key的hash值計算得到的下表和桶中的第一個位置元素產生了沖突,具體就是 //(1)key相同,value不同 //(2)只是通過hash值計算得到的下標相同,但是key和value都不同。這里處理的方法就是鏈表和紅黑樹 else {Node<K,V> e; K k;//上面已經計算得到了該hash對應的下標i,這里p=tab[i]。這里比較的有://(1)tab[i].hash是否等于傳入的hash。這里的tab[i]就是桶中的第一個元素//(2)比較傳入的key和該位置的key是否相同//(3)如果都相同,說明是同一個key,那么直接替換對應的value值(在后面會進行替換)if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) //將桶中的第一個元素賦給e,用來記錄第一個位置的值 e = p;//這里判斷為紅黑樹。hash值不相等,key不相等;為紅黑樹結點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); //前面的binCount是記錄鏈表長度的,如果該值大于8,就會轉變為紅黑樹 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash); break;}//如果在遍歷鏈表的時候,判斷得出要插入的結點的key和鏈表中間的某個結點的key相//同,就跳出循環,后面也會更新舊的value值if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break;//e = p.next。遍歷鏈表所用p = e; }}//判斷插入的是否存在HashMap中,上面e被賦值,不為空,則說明存在,更新舊的鍵值對if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null)e.value = value; //用傳入的參數value更新舊的value值 afterNodeAccess(e); return oldValue; //返回舊的value值} } //modCount修改 ++modCount; //容量超出就擴容 if (++size > threshold)resize(); afterNodeInsertion(evict); return null;}5.2、put方法執行過程總結

​可以看到主要邏輯在put方法中調用了putVal方法,傳遞的參數是調用了hash()方法計算key的hash值,主要邏輯在putVal中。可以結合注釋熟悉這個方法的執行,我在這里大概總結一下這個方法的執行:

1.首先 (tab = table) == null || (n = tab.length) == 0這一塊判斷hash桶是否為null,如果為null那么會調用resize方法擴容。后面我們會說到這個方法

2.定位元素在桶中的位置,具體就是通過key的hash值和hash桶的長度計算得到下標i,如果計算到的位置處沒有元素(null),那么就新建結點然后添加到該位置。

3.如果table[i]處不為null,已經有元素了,那么就表明產生hash沖突,這里可能是三種情況

①判斷key是不是一樣,如果key一樣,那么就將新的值替換舊的值;

②如果不是因為key一樣,那么需要判斷當前該桶是不是已經轉為了紅黑樹,是的話就構造一個TreeNode結點插入紅黑樹;

③不是紅黑樹,就使用鏈地址法處理沖突問題。這里主要就是遍歷鏈表,如果在遍歷過程中也找到了key一樣的元素,那么久還是使用新值替換舊值。否則會遍歷到鏈表結尾處,到這里就直接新添加一個Node結點插入鏈表,插入之后還需要判斷是不是已將超過了轉換為紅黑樹的閾值8,如果超過就會轉為紅黑樹。

4.最后需要修改modCount的值。

5.判斷插入后的size大小是不是超過了threshhold,如果超過需要進行擴容。

上面很多地方都涉及到了擴容,所以下面我們首先看看擴容方法。

六、HashMap的resize方法分析6.1、resize方法源碼

​擴容(resize)就是重新計算容量,具體就是當map內部的size大于DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY ,就需要擴大數組的長度,以便能裝入更多的元素。resize方法實現中是使用一個新的數組代替已有的容量小的數組。

//該方法有2種使用情況:1.初始化哈希表(table==null) 2.當前數組容量過小,需擴容final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; //oldTab指向舊的table數組 //oldTab不為null的話,oldCap為原table的長度 //oldTab為null的話,oldCap為0 int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; //閾值 int newCap, newThr = 0; if (oldCap > 0) { //這里表明oldCap!=0,oldCap=原table.length();if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; //如果大于最大容量了,就賦值為整數最大的閥值 return oldTab;}// 如果數組的長度在擴容后小于最大容量 并且oldCap大于默認值16(這里的newCap也是在原來的//長度上擴展兩倍)else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold雙倍擴展threshhold } else if (oldThr > 0) // initial capacity was placed in threshold//這里的oldThr=tabSizeFor(initialCapacity),從上面的構造方法看出,如果不是調用的//無參構造,那么threshhold肯定都會是經過tabSizeFor運算得到的2的整數次冪的,所以可以將//其作為Node數組的長度(個人理解)newCap = oldThr; else { // zero initial threshold signifies using defaults(零初始閾值表示使用默認值)//這里說的是我們調用無參構造函數的時候(table == null,threshhold = 0),新的容量等于默//認的容量,并且threshhold也等于默認加載因子*默認初始化容量newCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } // 計算新的resize上限 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數組存放結點元素 //當然,桶數組的初始化也是在這里完成的 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; //原來的table不為null if (oldTab != null) {// 把每個bucket都移動到新的buckets中for (int j = 0; j < oldCap; ++j) { Node<K,V> e; //原table中下標j位置不為null if ((e = oldTab[j]) != null) {oldTab[j] = null; //將原來的table[j]賦為null,及時GC?if (e.next == null) //如果該位置沒有鏈表,即只有數組中的那個元素 //通過新的容量計算在新的table數組中的下標:(n-1)&hash newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) //如果是紅黑樹結點,重新映射時,需要對紅黑樹進行拆分 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { // 鏈表優化重hash的代碼塊 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) { //loTail處為null,那么直接加到該位置 if (loTail == null) loHead = e; //loTail為鏈表尾結點,添加到尾部 elseloTail.next = e; //添加后,將loTail指向鏈表尾部,以便下次從尾部添加 loTail = e;}// 原位置+舊容量else { //hiTail處為null,就直接點添加到該位置 if (hiTail == null)hiHead = e; //hiTail為鏈表尾結點,尾插法添加 elsehiTail.next = e; hiTail = e;} } while ((e = next) != null); // 將分組后的鏈表映射到新桶中 // 原索引放到bucket里 if (loTail != null) {//舊鏈表遷移新鏈表,鏈表元素相對位置沒有變化; //實際是對對象的內存地址進行操作 loTail.next = null;//鏈表尾元素設置為nullnewTab[j] = loHead; //數組中位置為j的地方存放鏈表的head結點 } // 原索引+oldCap放到bucket里 if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead; }} }} } return newTab;}6.2、(e.hash & oldCap) == 0分析

​我這里添加上一點,就是為什么使用 (e.hash & oldCap) == 0判斷是處于原位置還是放在更新的位置(原位置+舊容量),解釋如下:我們知道capacity是2的冪,所以oldCap為10...0的二進制形式(比如16=10000B)。

(1)若判斷條件為真,意味著oldCap為1的那位對應的hash位為0(1&0=0,其他位都是0,結果自然是0),對新索引的計算沒有影響,至于為啥沒影響下面就說到了。先舉個例子計算一下數組中的下標在擴容前后的變化:

深入理解Java中的HashMap

​從上面計算發現,當cap為1的那位對應的hash為0的時候,resize前后的index是不變的。我們再看下面,使用上面的hash值,對應的就是 (e.hash & oldCap) == 0,恰好也是下標不變的

深入理解Java中的HashMap

​(2)若判斷條件為假,則 oldCap為1的那位對應的hash位為1。比如新下標=hash&( newCap-1 )= hash&( (16<<2) - 1)=10010,相當于多了10000,即 oldCap .如同下面的例子

深入理解Java中的HashMap

​從上面計算發現,當cap為1的那位對應的hash為1的時候,resize前后的index是改變的。我們再看下面,使用上面的hash值,對應的就是 (e.hash & oldCap) != 0,恰好下標就是原索引+原容量

深入理解Java中的HashMap

6.3、部分代碼理解

​這一部分其實和put方法中,使用鏈地址法解決hash沖突的原理差不多,都是對鏈表的操作。

// 原位置if ((e.hash & oldCap) == 0) { //loTail處為null,那么直接加到該位置 if (loTail == null) loHead = e; //loTail為鏈表尾結點,添加到尾部 elseloTail.next = e; //添加后,將loTail指向鏈表尾部,以便下次從尾部添加 loTail = e;}// 原位置+舊容量else { //hiTail處為null,就直接點添加到該位置 if (hiTail == null)hiHead = e; //hiTail為鏈表尾結點,尾插法添加 elsehiTail.next = e; hiTail = e;}

​我們直接通過一個簡單的圖來理解吧

深入理解Java中的HashMap

6.4、resize總結

​resize代碼稍微長了點,但是總結下來就是這幾點

判斷當前oldTab長度是否為空,如果為空,則進行初始化桶數組,也就回答了無參構造函數初始化為什么沒有對容量和閾值進行賦值,如果不為空,則進行位運算,左移一位,2倍運算擴容。擴容,創建一個新容量的數組,遍歷舊的數組:如果節點為空,直接賦值插入如果節點為紅黑樹,則需要進行進行拆分操作(個人對紅黑樹還沒有理解,所以先不說明)如果為鏈表,根據hash算法進行重新計算下標,將鏈表進行拆分分組(相信看到這里基本上也知道鏈表拆分的大致過程了)

七、HashMap的get方法分析7.1、get方法源碼

​基本邏輯就是根據key算出hash值定位到哈希桶的索引,當可以就是當前索引的值則直接返回其對于的value,反之用key去遍歷equal該索引下的key,直到找到位置。

public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value;}final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; //計算存放在數組table中的位置.具體計算方法上面也已經介紹了 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) { //如果first為紅黑樹結點,就在紅黑樹中遍歷查找 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;}

以上就是深入理解Java中的HashMap的詳細內容,更多關于Java HashMap的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 日韩国产欧美视频 | 亚洲精品综合在线 | 黄色免费网站在线看 | 亚洲每日更新 | 亚洲一区二区久久 | 免费黄色小视频 | 亚洲男人天堂网 | 91麻豆视频| 久久久久久成人 | 色偷偷噜噜噜亚洲男人 | 国产精品久久久999 成人亚洲视频 | 精品国产91亚洲一区二区三区www | 久久99精品国产.久久久久 | 狠狠做深爱婷婷综合一区 | h视频免费在线 | 国产精品视频一区二区三区 | 国产精品久久久久久久久久小说 | 国产91久久精品 | 四色成人av永久网址 | 理论黄色片 | 精品久久久久久久久久久久久久久久久久 | 国产黄色大片免费看 | 久草在线免费福利资源 | 亚洲一区二区三区中文字幕 | 国产羞羞视频在线观看 | 国产一区精品视频 | 9 1在线观看 | 男女啪啪高清无遮挡 | 中文字幕亚洲在线 | 亚洲乱码国产乱码精品精 | 中文字幕日韩在线 | 久久伊人精品视频 | 久久成人国产精品 | 国产精品美女久久久久久久久久久 | 国产成人无遮挡在线视频 | 欧美成人在线免费视频 | 国产18av | 欧美一级免费在线观看 | 九一亚洲精品 | 国产精品禁久久精品 | 国产欧美精品一区二区色综合 | 特一级黄色片 | 日韩午夜电影在线观看 | 中文字幕高清 | 在线成人av| 蜜桃精品久久久久久久免费影院 | 网址av| 亚洲视频免费在线观看 | 亚洲a人 | 在线日韩 | 超碰人人爽 | 亚洲卡一 | 婷婷丁香激情 | 午夜午夜精品一区二区三区文 | 国产精品中文字幕在线 | 91精品国产综合久久久久久丝袜 | 久久密| 精品久久久久久久久久久久 | 久久伊| 日本欧美一区二区 | 精品第一页 | 成年人精品视频在线观看 | 亚洲精品美女久久久 | 好看毛片 | 国产一区亚洲 | 天天干夜夜骑 | 亚洲一区二区黄 | 欧美黄色网 | 久久国产精品视频 | 五月婷婷婷婷 | 日本高清视频在线播放 | 亚洲精品三级 | 超碰在线人 | 国产精品美女久久久久久久久久久 | 天天干夜夜操 | 一区在线视频 | 狠狠草视频 | 国产精品久久久久久久久免费高清 | 午夜窝窝 | 成人在线h | 亚洲福利在线观看 | 国产成人精品久久 | 成人一级片视频 | 久久久亚洲一区 | 亚洲欧洲日韩 | 国产日韩一区 | 亚洲精品中文字幕中文字幕 | 欧美日韩精品一区二区在线播放 | 北条麻妃一区二区在线 | 青青草在线视频免费观看 | 精品久久久久久久久久久久久久久久久久久 | 欧美精品一二三区 | 欧美 日韩 国产 成人 在线 | 久久综合九色综合欧美狠狠 | 国产三级精品三级 | 欧美日韩中文在线 | 久久国产精品久久久久久 | 免费观看欧美一级 | 久久福利 | 特黄视频 | 国产欧美久久久久久 | xxxx性欧美| 永久精品 | 国产精品视频一区二区三区不卡 | 四季久久免费一区二区三区四区 | 欧美成人精品一区二区男人看 | 蜜桃视频在线播放 | 欧美a在线 | 欧美日韩成人在线 | 99久久99久久精品 | 亚洲欧美中文日韩v在线观看 | 欧美日韩成人在线播放 | 久久天堂电影 | 欧美99 | 国产精品.xx视频.xxtv | 羞羞视频在线免费观看 | 中字幕视频在线永久在线观看免费 | 四虎永久免费影视 | а天堂中文最新一区二区三区 | 欧美日韩中文 | 精品视频一区二区三区四区 | 夜夜天天 | 成人a在线观看 | 久久久精品日本 | 一区二区三区国产精品 | 黄色大片免费网站 | aaa级片 | 一级做a爰| 中文字幕亚洲一区 | 亚洲高清视频在线观看 | 国产欧美精品一区二区三区 | 日韩精品视频在线播放 | 亚洲成人久久久 | 欧美国产在线视频 | 色婷婷狠狠 | 国产成人在线视频 | 日韩精品 | 国产天天操 | 2019中文字幕在线观看 | 黄色在线观看网址 | 午夜国产视频 | 成人高清av | 在线视频自拍 | 成全视频免费观看在线看黑人 | 在线视频91 | 国产一区二区三区免费观看 | 自拍视频在线观看免费 | 亚洲电影在线观看 | 超碰激情| 久久综合久 | 6080夜射猫| 中文字幕亚洲视频 | 色噜噜视频在线观看 | 日韩中文字幕在线视频 | 一区二区不卡视频 | 午夜小视频在线观看 | 三区在线 | 成人精品在线视频 | 91欧美激情一区二区三区成人 | 天天综合永久入口 | 欧美精品久久久久久久久老牛影院 | 欧美一区日韩一区 | 国产美女久久久 | 91香蕉视频| 国产在线一 | 久久亚洲精品国产一区 | 国产精品成人一区二区三区夜夜夜 | 成人精品一区二区三区中文字幕 | 久久大 | 精品三级在线观看 | 久草色视频在线观看 | 亚洲无吗电影 | 波多野结衣一区二 | 久久国产一区二区 | 中文字幕乱码一区二区三区 | 欧美顶级毛片在线播放 | 欧美日韩一级二级三级 | 一区二区免费在线观看 | 欧美精品久久久久久久久久丰满 | 精品久久久久久久久久久 | 在线观看国产 | 国精产品一区一区三区免费完 | 一级片免费视频 | 高清国产午夜精品久久久久久 | 天天久| 日韩在线视频免费 | 91精品国产一区二区 | 99国产视频 | 欧美黄色一区 | 成人免费视频 | 久久在线播放 | 国产精品久久久久久中文字 | 国产精品久久久久久久久污网站 | 一级黄色生活视频 | 亚洲综合视频 | 国产有码 | 国产精品久久久久久久久久久久久久 | h片观看 | 中文在线一区二区 | 青青草一区二区三区 | 午夜在线小视频 | 国产欧美亚洲精品 | 97狠狠| 久久se精品一区精品二区 | 91精品国产综合久久久久久 | 日韩欧美视频 | 久久99精品国产自在现线 | 中文字幕日韩在线 | 久久一二区 | 欧美一区二区三区免费 | 99精品欧美一区二区三区 | 午夜精品网站 | 91精品国产综合久久久久久漫画 | 亚洲免费不卡视频 | 国产精品久久婷婷六月丁香 | √新版天堂资源在线资源 | 精品视频一区二区三区四区 | 精品欧美一区二区在线观看 | 国产精品无码专区在线观看 | 国产高清一区二区 | 日韩中文字幕三区 | 中文字幕亚洲精品 | 国产超碰人人模人人爽人人添 | 日本亚洲一区 | 久草在线视频免费播放 | 久久国产视屏 | 欧美成人资源 | 久久国内精品 | 日日爽| 日韩精品在线网站 | 毛片链接 | 三级成人在线 | 99re在线观看 | 国产精品色婷婷久久58 | 亚洲伊人成人 | 精品久久久久久国产 | 国产日韩精品入口 | 国产成人久久777777 | 国产亚洲一区二区三区在线观看 | 久久精品国产99国产精品 | 国产精品影院在线观看 | 北条麻妃99精品青青久久主播 | 伊人久操 | 日韩城人网站 | 成人欧美一区二区三区色青冈 | 涩涩视频在线看 | 亚洲高清在线观看 | 日韩一区二区在线观看 | 日本视频一区二区三区 | 噜噜噜在线 | 久久小草 | 日韩精品一区二区三区中文在线 | 麻豆精品一区二区 | 亚洲免费视频在线 | 97精品超碰一区二区三区 | 91福利网站在线观看 | 国产精品视频免费观看 | 久久在线 | 特黄一级| 色综合区 | 国产精品第一 | 久久久精品久久久久久 | av高清在线免费观看 | 欧美日韩视频在线第一区 | 一区二区三区在线免费播放 | 性色av一二三杏吧传媒 | 白浆在线 | 亚洲不卡在线 | 不卡视频一二三区 | 成人精品一区二区 | 亚洲高清在线 | 亚洲第一区在线 | 国精产品99永久一区一区 | 天天操综| 亚洲一区二区三区视频 | 亚洲少妇视频 | 久久久久国产一区二区三区四区 | 激情视频网站 | 暖暖日本在线视频 | 一级做a爰片性色毛片 | 国产一极毛片 | 天天操夜夜爽 | 亚洲欧美国产毛片在线 | 影音先锋国产 | 日韩中文在线 | 婷婷久久五月 | 欧洲一区二区在线观看 | 亚洲国产成人久久一区二区三区 | 欧美日韩国产一区 | 91久久精品久久国产性色也91 | 奇米av | 国产一区二区久久久 | 自拍亚洲 | 一级在线观看视频 | 成人午夜免费网站 | 4hu网站 | 亚洲精品成人av | 色视频在线免费观看 | 中文字幕一区二区在线观看 | 久久久一区二区三区 | 中文一区 | 日韩欧美一区二区三区免费观看 | 日韩高清在线一区 | 国产一级淫片a级aaa | 日韩电影在线看 | 成人在线视频一区二区 | 日本一区不卡 | 国产特级毛片 | 九九精品视频在线 | 在线观看污片 | 欧美乱淫 | 欧美成人一区二区三区片免费 | 久久精品这里热有精品 | 日韩性在线| 欧美日韩在线一 | 欧美日韩伊人 | 国产视频导航 | 午夜激情免费在线观看 | 在线看av的网址 | 国产乱码精品一区二区三区忘忧草 | 91成人黄色 | 在线二区| 国产一区二区三区av在线 | 日本一二三区视频 | 黄网站在线播放 | 精品免费视频 | 亚洲精品视频在线观看网站 | 欧美一级在线观看视频 | 久久噜噜噜精品国产亚洲综合 | 精品国产乱码一区二区三区a | 日韩欧美~中文字幕 | 一级黄视频 | 毛片免费观看 | 国产乱码精品一区二区三区中文 | 国产精品视屏 | 91精品国产高清一区二区三区 | 精品成人av | 国产精久久久久久久妇剪断 | 成人精品视频在线观看 | 日韩免费视频一区二区 | 国产综合一区二区 | 亚洲三区在线观看 | 看亚洲a级一级毛片 | 中国1级黄色片 | 成人av免费观看 | 在线一区观看 | 日韩在线免费电影 | 精品亚洲一区二区三区 | 91麻豆精品久久久久蜜臀 | 情五月| 国产久精品 | 操久久| 啪一啪| 视频成人免费 | 久久aⅴ国产欧美74aaa | 日韩欧美a级v片免费播放 | 蜜桃视频一区二区三区 | 亚洲精品一区二区三区在线 | 欧美日产国产成人免费图片 | 9999亚洲| 波多野结衣先锋影音 | 亚洲精品一区在线观看 | 国产区区| 久久婷婷色 | 日韩一区二区三区在线观看 | 成人午夜免费视频 | 国产精品999 | 黄色官网在线观看 | 日韩国产在线 | 日本videos18高清hd下 | 国产一区二区免费 | 精品中文久久 | 一级大片免费观看 | 激情久久久 | 精品乱子伦一区二区三区 | 日本在线不卡视频 | 日本久久久久久久久久 | 成人av影院 | 午夜欧美一区二区三区在线播放 | 午夜爽 | 99re视频 | 成人欧美一区二区三区视频xxx | 91免费看片神器 | 国产亚洲精品精品国产亚洲综合 | www.久久.com | 国产一区久久精品 | 荡女妇边被c边呻吟视频 | 波多野结衣一二三四区 | 九一视频在线免费观看 | 日韩欧美一区二区三区四区 | 99热精品在线 | 国产精品jizz在线观看麻豆 | 亚洲视频在线免费观看 | 欧美一级精品片在线看 | 91麻豆产精品久久久久久 | 亚洲精品一区二三区不卡 | 天天天天综合 | 青青久久北条麻妃 | 亚洲情综合五月天 | 麻豆一区一区三区四区 | 91在线中文字幕 | 国产 在线 | 日韩 | 亚洲久久一区 | 影音先锋久久 | 成人黄色在线视频 | 国产精品久久久久久亚洲调教 | 日韩欧美精品一区二区三区 | 亚洲第一男人天堂 | 日韩高清一区二区 | 国产乱码精品一品二品 | 亚洲天天干 | 久久久麻豆 | 亚洲tv久久爽久久爽 | 国产亚洲精品久久久闺蜜 | 国产精品96久久久久久久 | 国产精品久久久久久影院8一贰佰 | 激情欧美日韩一区二区 | 亚洲一区二区三区国产 | 成人在线观看免费视频 | 高清三区 | 午夜视频免费 | 国产精品久久精品 | 人人玩人人添人人澡97 | 国产一区| 一区二区在线视频 | 精一区二区| 亚洲成av人乱码色午夜 | 精品护士一区二区三区 | 久久久久一区二区 | 精品国产一区二区 | 久久久久久久久久久久久av | 毛片黄片| 成人小视频在线观看 | 久久1区| 国产一区二区毛片 | 91免费观看国产 | 中国大陆高清aⅴ毛片 | 欧美日韩一区二区三区 | 欧美精品区 | 欧美中文在线 | 国产亚洲欧美在线 | 亚洲国产精品久久 | av伊人网| 久久第一区| 91在线视频在线 | 国产玖玖| 亚洲啊v| 亚洲人成中文字幕在线观看 | 日韩中文久久 | av一级毛片| av成人在线观看 | 99精品免费在线 | 欧美一区二区三区免费 | 国产一区二区三区免费 | 国产在线精品一区二区三区 | 久久线视频 | 俺要去97中文字幕 | 日本中文字幕在线观看 | 色综合成人 | 欧美一区2区三区4区公司二百 | 亚洲视频在线看 | 精品美女在线 | 亚洲一区二区免费看 | 九九亚洲 | 国产免费成人 | 日韩高清中文字幕 | 高清久久 | 黄色a级网站 | 成人激情在线 | 久久久精品一区二区三区 | 成人精品一区二区三区 | 国产乱码一区二区三区 | 久久久久久免费毛片精品 | 久久久久国产精品免费免费搜索 | 欧美一区二区三区在线视频 | 人人种亚洲 | 欧美精品日韩 | 一色桃子av一区二区免费 | 国产免费看 | 在线欧美亚洲 | 北条麻妃一区二区在线 | 亚洲国产成人av好男人在线观看 | 日韩三区在线 | 国产一级黄色av | 日本不卡精品 | 久草新| 欧美1区| 91精品国产综合久久久久久 | 成人网址在线观看 | 欧美2区 | 国产亚洲欧美一区 | 国产精品久久久久久久午夜 | 国产一区精品电影 | 欧美视频三区 | 欧美专区中文字幕 | 国产激情精品一区二区三区 | 精品美女一区 | 国产中文字幕在线观看 | 久久精品 | 黄色片免费在线观看视频 | 香蕉成人啪国产精品视频综合网 | 日韩精品1区2区3区 国产精品国产成人国产三级 | 视频一区 中文字幕 | 日韩欧美在线播放 | 福利精品视频 | www.色在线 | 中国大陆高清aⅴ毛片 | 亚洲a在线观看 | 日韩视频一区在线观看 | av毛片在线免费看 | 国产精品永久免费 | 欧美激情综合色综合啪啪五月 | 欧美激情国产日韩精品一区18 | 久久久国产精品入口麻豆 | 国产精彩视频 | 黄色一级电影免费观看 | 国产成人福利在线观看 | 亚洲 中文 欧美 日韩 在线观看 | 成人精品视频在线观看 | 国产精品美女久久久久aⅴ国产馆 | 国产91精品在线 | 久久线视频 | 亚洲国产精品一区 | 九色一区 | 在线看欧美 | 国产免费一区二区三区 | 亚洲性视频网站 | 中文字幕av一区二区 | 久久一区二区视频 | 色综合天天综合网国产成人网 | 欧美国产一区二区三区 | 中文久久| 精品国产一区二区三区性色av | eeuss国产一区二区三区四区 | 欧美一级免费播放 | 日韩毛片在线观看 | 福利视频三区 | 成人国产综合 | 成人免费视频网站 | 欧美日韩中文字幕 | 成人在线免费观看 | 国产精品99久久久久久动医院 | 久久精品性 | 日韩电影免费在线观看中文字幕 | 91中文字幕在线 | 不卡免费在线视频 | 老司机精品福利视频 | 精品xxxx户外露出视频 | 亚洲精品91 | 91在线视频福利 | 四虎影院最新网址 | 精品久久国产 | 国产美女网站 | 亚洲欧美日韩在线一区二区三区 | 日韩成人在线播放 | 亚洲一区二区福利 | 91成人一区| 日韩 国产 在线 | 91麻豆精品国产91久久久久久久久 | 日韩av中文在线 | 国产一区二区精品久久岳 | 91精品国产综合久久久久久 | 日日干天天操 | 日韩中文字幕一区二区 | 欧美日韩国产在线看 | 久久久www成人免费精品 | 在线免费成人 | 婷婷久久综合 | 亚州中文 | 国产午夜精品一区二区 | 碰碰视频 | 蜜臀视频在线观看 | 日韩成人不卡 | 91久色| 99亚洲精品| 国产毛片精品 | 日日干夜夜干 | 亚洲精品国产电影 | 久久久久国产一区二区三区 | 久久久精品一区二区三区 | 欧美一级网 | 国产一区久久 | 国产一区二区三区四区五区加勒比 | 亚洲美女网址 | 国产成人av一区二区三区 | 久草久草 | 国产精品久久 | 日本手机在线视频 | 黄网在线免费观看 | 羞羞的视频在线 | 久久99精品久久久久久琪琪 | 99re6在线视频精品免费 | 久久男人的天堂 | 欧美视频二区 | 成人午夜在线视频 | 国产日韩欧美综合 | 毛片a级片 | 蜜桃中文字幕 | 91精品免费在线观看 | 国产精品丝袜视频 | 99视频精品在线 | 国产精品久久久久久久久久免费看 | 亚洲精品国产9999久久久久 | 亚洲日本午夜 | 亚洲 中文 欧美 日韩 在线观看 | 亚洲国产精品一区二区久久 | 国产精品日韩一区二区 | 久久一日本道色综合久久 | www.男人天堂| 国产精品2区| 日韩免费网站 | 国产成人精品av | 日本成人一二三区 | 免费观看视频www | 91麻豆精品国产91久久久资源速度 |