成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

基礎篇:Java集合,面試專用

開發 后端
CopyOnWriteArrayList 的線程安全:CopyOnWriteArrayList 在寫的時候會加鎖,為了保證寫安全,會在寫操作時復制一個新數組來操作,然后覆蓋舊的數組;不會影響讀的性能。

本文轉載自微信公眾號「潛行前行」,作者 cscw。轉載本文請聯系潛行前行公眾號。

沒啥好說的,在座的各位都是靚仔

  • List 數組
  • Vector 向量
  • Stack 棧
  • Map 映射字典
  • Set 集合
  • Queue 隊列
  • Deque 雙向隊列

一般隊列的通用方法

操作方法 拋出異常 阻塞線程 返回特殊值 超時退出
插入元素 add(e) put(e) offer(e) offer(e, timeout, unit)
移除元素 remove() take() poll() pull(timeout, unit)
檢查 element() peek()

1.List 數組

  • 元素按進入先后有序保存,可重復
  • List有兩種底層實現,一種是數組,一種是鏈表,而鏈表的實現繼承了 Collection。數組和集合的區別:
    • 數組大小是固定,集合是可變的
    • 數組的元素可以基本類型也可以是引用類型,而集合只能是引用類型

ArrayList

  • ArrayList底層是使用一個可動態擴容的數組,與普通數組的區別就是它是沒有固定大小的限制,可以添加或刪除元素
  • 它的特點就是讀速度、更新快,增刪慢;內存相鄰,根據Index讀取的時間復雜度是O(1);可以存儲重復元素,但線程不安全
  • ArrayList 的擴容機制
  1. //ArrayList openJDK 13 
  2. private void add(E e, Object[] elementData, int s) { 
  3.     if (s == elementData.length) //放不下了 
  4.         elementData = grow(); // 擴容 
  5.     elementData[s] = e; 
  6.     size = s + 1; 
  7. private Object[] grow() { 
  8.     return grow(size + 1); 
  9. private Object[] grow(int minCapacity) { 
  10.     int oldCapacity = elementData.length; 
  11.     if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 
  12.         int newCapacity = ArraysSupport.newLength(oldCapacity, 
  13.                 minCapacity - oldCapacity,  // minCapacity - oldCapacity == 1 
  14.                 oldCapacity >> 1 ); // oldCapacity == 1/2 oldCapacity 
  15.         return elementData = Arrays.copyOf(elementData, newCapacity); 
  16.     } else { 
  17.         return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)]; 
  18.     } 
  • 如果當前元素放不下,則擴容至 1.5 倍,且大于等于 1
  1. // ArraysSupport.newLength 
  2. public static int newLength(int oldLength, int minGrowth, int prefGrowth) { 
  3.     //prefGrowth 是 oldLength 的 1/2,minGrowth 是 1。因此 newLength = 1.5 oldLength 
  4.     int newLength = Math.max(minGrowth, prefGrowth) + oldLength; 
  5.     if (newLength - MAX_ARRAY_LENGTH <= 0) { // MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8 
  6.         return newLength; 
  7.     } 
  8.     return hugeLength(oldLength, minGrowth); 

LinkedList

  • LinkedList的節點并不是存儲真實的數據,而是存下數據的引用對象,而且節點之間使用引用相關聯
  • LinkedList實現了Queue、Deque接口,可作為隊列使用;查找慢,增刪快,可以存儲重復元素,但線程不安全
  • 使用 LinkedList 實現LRU
  1. public static class LRU<T> { 
  2.     //默認的緩存大小 
  3.     private  int CAPACITY = 0; 
  4.     //引用一個雙向鏈接表 
  5.     private LinkedList<T> list; 
  6.     //構造函數 
  7.     public LRU(int capacity) { 
  8.         this.CAPACITY = capacity; 
  9.         list = new LinkedList(); 
  10.     } 
  11.     //添加一個元素 
  12.     public synchronized void put(T object) { 
  13.         if (list != null && list.contains(object)) { 
  14.             list.remove(object); 
  15.         } 
  16.         removeLeastVisitElement(); 
  17.         list.addFirst(object); 
  18.     } 
  19.     //移除最近訪問次數最少的元素 
  20.     private void removeLeastVisitElement() { 
  21.         int size = list.size(); 
  22.         //注意,這兒必須得是CAPACITY - 1否則所獲的size比原來大1 
  23.         if (size > (CAPACITY - 1)) { 
  24.             Object object = list.removeLast(); 
  25.         } 
  26.     } 
  27.     //獲取第N個索引下面的元素 
  28.     public  T get(int index) { 
  29.         return list.get(index); 
  30.     } 
  • LinkedList 的 API
  1. public E getFirst() //獲取第一個元素 
  2. public E getLast()  //獲取最后一個元素 
  3. public E removeFirst() // 移除第一個元素,并返回 
  4. public E removeLast() // 移除最后一個元素,并返回 
  5. public void addFirst(E e) //加入頭部 
  6. public void addLast(E e)  //加入尾部 
  7. public void add(E e) //加入尾部 
  8. public boolean contains(Object o) //是否包含 元素 o 
  9. public E peek() //獲取頭部第一個元素 
  10. public E element()  // 獲取頭部第一個元素,不存在則報錯 
  11. public E poll() //獲取頭部第一個元素,并移除 
  12. public boolean offer(E e) // 調用 add(E e) 
  13. public boolean offerFirst(E e) // 調用 addFirst 
  14. public boolean offerLast(E e) // 調用 addLast 
  15. public void push(E e) //在頭部壓入一個元素 
  16. public E pop()  //彈出第一個元素,并移除。不存在則報錯 
  • ArrayList 和 LinkedList 使用場景
    • 頻繁訪問列表中的某一個元素,或者需要在列表末尾進行添加和刪除元素操作,用ArrayList
    • 頻繁的在列表開頭、中間、末尾等位置進行添加和刪除元素操作,用LinkedList

Iterator 和 fast-fail、fail-safe機制

  • Java Iterator(迭代器)不是一個集合,它是一種用于訪問集合的方法,可用于迭代 List 和 Set 等集合,主要有hashNext(),next(),remove()三種方法
  • fail-fast 是Java集合(Collection)的一種錯誤機制。當多個線程對同一個集合進行修改結構操作,使用集合的迭代器iterator,會首先檢測是否有對集合的并發修改,進而產生ConcurrentModificationException 異常提示
  • fail-safe:保證在對任何集合結構的修改操作都基于 《復制-修改》 進行的,即先copy一個新的集合對象,然后對新的集合對象進行修改,最后將新的集合對象替換掉老的集合對象(老的集合對象的地址指向新的集合對象)。java.util.concurrent包下采用的是fail-safe機制。
    • 缺點1-對集合的復制copy會產生大量的對象,造成內存空間的浪費。
    • 缺點2-無法保證集合迭代過程中獲取的集合數據是最新的內容

CopyOnWriteArrayList

  • CopyOnWriteArrayList 的線程安全:CopyOnWriteArrayList 在寫的時候會加鎖,為了保證寫安全,會在寫操作時復制一個新數組來操作,然后覆蓋舊的數組;不會影響讀的性能
  1. public class CopyOnWriteArrayList<E> 
  2.     implements List<E>, RandomAccess, Cloneable, java.io.Serializable { 
  3.     //可重入鎖 
  4.     final transient ReentrantLock lock = new ReentrantLock(); 
  5.     //數組,僅通過get和set方法操作 
  6.     private transient volatile Object[] array;  
  7.     .... 
  8.     public boolean add(E e) { 
  9.         final ReentrantLock lock = this.lock; 
  10.         lock.lock(); 
  11.         try { 
  12.             Object[] elements = getArray();//拿到當前數組 
  13.             int len = elements.length;//獲得長度 
  14.             //拷貝當前數組 
  15.             Object[] newElements = Arrays.copyOf(elements, len + 1); 
  16.             newElements[len] = e; 
  17.             setArray(newElements); //調用set方法將新數組設置為當前數組 
  18.             return true
  19.         } finally { 
  20.             lock.unlock();//解鎖 
  21.         } 
  22.     } 
  • CopyOnWriteArrayList 的缺點
    • CopyOnWrite 在進行寫操作的時候,內存里會同時駐扎兩個對象的內存,導致內存的浪費
    • CopyOnWrite 容器只能保證數據的最終一致性,不能保證數據的實時一致性。如果你希望寫入的的數據,馬上能讀到,請不要使用CopyOnWrite容器,沒有阻塞等待的概念
  • CopyOnWriteArrayList 和 Collections.synchronizedList 區別
    • CopyOnWriteArrayList 的寫操作性能較差,而多線程的讀操作性能較好
    • Collections.synchronizedList的寫操作性能比CopyOnWriteArrayList在多線程操作的情況下要好很多,而讀操作因為是采用了 synchronized關鍵字的方式,其讀操作性能并不如CopyOnWriteArrayList

線程安全的List

  • A:使用 Vector;B:使用 Collections.synchronized() 返回線程安全的 List;C:使用 CopyOnWriteArrayList

List的API示例

  1. boolean contains(Object o) // 是否包含 o 
  2. boolean isEmpty(); // 是否為空 
  3. int size(); //集合元素 
  4. Iterator<E> iterator(); // 返回迭代器 
  5. Object[] toArray(); // 轉為 Object數組 
  6. <T> T[] toArray(T[] a); // 轉為具體類型數組 
  7. boolean add(E e); // 加入尾部 
  8. boolean remove(Object o); // 移除 o 
  9. boolean containsAll(Collection<?> c); //是否報考 集合 c 
  10. boolean addAll(Collection<? extends E> c);// 合并 c  
  11. boolean retainAll(Collection<?> c);//保留只存在集合 c 的元素 
  12. void clear(); // 清除集合元素 
  13. void sort(Comparator<? super E> c) //根據 Comparator 排序 
  14. E get(int index); // 根據下標獲取 元素 
  15. set(int index, E element); // 設置第 index 的元素 
  16. E remove(int index); // 移除 第 index 的元素 
  17. <E> List<E> of(E e1.....) // jdk 9 
  18. List<E> copyOf(Collection<? extends E> coll)  // 復制 

2.Vector(向量)

ArrayList 和 Vector、LinkedList 的區別

  • Vector 相當于是 ArrayList 線程安全的翻版
  • Vector 繼承實現List 特點: 底層數據結構是數組,查詢快,線程安全

Vector 的API示例

  1. boolean synchronized contains(Object o); 
  2. boolean synchronized isEmpty(); 
  3. boolean synchronized containsAll(Collection<?> c); 
  4. boolean addAll(Collection<? extends E> c); 
  5. public synchronized boolean add(E e) 
  6. public synchronized E get(int index); 
  7. public synchronized E set(int index, E element); 
  8. public synchronized E firstElement() 
  9. public synchronized void removeElementAt(int index
  10. public synchronized E lastElement() 
  11. public synchronized void setElementAt(E obj, int index
  12. public synchronized E remove(int index
  13. public void clear() 
  14. Iterator<E> iterator(); 

3.Stack(棧)

  • Stack 是 Vector提供的一個子類,用于模擬"棧"這種數據結構(LIFO后進先出)
  • 線程安全,允許 null 值

Stack 的API示例

  1. public E push(E item) //推入棧頂 
  2. public synchronized E pop() // 彈出棧頂元素,不存在則報錯 
  3. public synchronized E peek() // 獲取棧頂元素,不移除 
  4. public boolean empty()  // 棧是否為空 
  5. public synchronized int search(Object o) // 搜索元素  

4.Map

  • Map 用于保存具有映射關系的數據,Map里保存著兩種映射的數據:key和value,它們都可以使任何引用類型的數據,但key不能重復。所以通過指定的key就可以取出對應的value
  • 請注意!!!Map 沒有繼承 Collection 接口

TreeMap(1.8JDK)

  • 繼承 AbstractMap,TreeMap 是基于紅黑樹實現,可保證在log(n)時間復雜度內完成 containsKey,get,put 和 remove 操作,效率很高。(紅黑樹的原理這里不展開講,后面會專門寫一篇)
  • 另一方面,由于 TreeMap 基于紅黑樹實現,因此 TreeMap 的鍵是有序的

HashMap

  • HashMap 繼承AbstractMap類實現了Map,是一個散列表,它存儲的內容是鍵值對(key-value)映射。HashMap 實現了 Map 接口,根據鍵的 HashCode 值存儲數據,具有很快的訪問速度,最多允許一條記錄的鍵為 null,不支持線程同步。HashMap 是無序的,即不會記錄插入的順序
  • HashMap如何處理hash沖突,hash沖突的幾種解決方法
    • 鏈地址法-如果存在 hash 碰撞,則創建一鏈表存儲相同的元素
    • 開放定址法容易導致 hash 碰撞,查詢慢
    • 線性探查在散列的時候,如果當前計算出的位置已經被存儲,那么就順序的向后查找,知道找到空位置或則是所有位置均不為空失敗
    • 二次探查使用一個輔助散列函數,使得后續的探查位置在前一個探查位置上加上一個偏移量,該偏移量以二次方的形式依賴于探查號i。二次探查的散列函數形式為:h(k,i)=(h'(k,i)+c1*i + c2 * i^2) mod m
    • 雙重散列使用兩個輔助散列函數h1和h2,初始的散列位置是h1(k),后續的散列位置在此基礎上增加一個偏移量h2(k)*i mod m
    • 開放定址法
    • 鏈地址法
  • HashMap 底層實現是數組+鏈表+紅黑樹??諈⒌腍ashMap初始容量是16,默認加載因子為0.75。取值0.75是因為 0.5 容易浪費空間,取值 1 則需要填滿每一個桶,實際情況很難達到,會產生大量的哈希碰撞。因此取中間值
  • HashMap 的容量一般是 2 的冪次方,可直接使用“位與”計算 hash 值,相對取模計算 hash 快

Hashtable

  • 繼承于Dictionary,現在基本已被淘汰
  • HashTable的操作幾乎和HashMap一致,主要的區別在于HashTable為了實現多線程安全,在幾乎所有的方法上都加上了synchronized鎖,而加鎖的結果就是HashTable操作的效率十分低下
  • HashMap允許有一個鍵為null,允許多個值為null;但HashTable不允許鍵或值為null
  • Hash映射:HashMap的hash算法通過非常規設計,將底層table長度設計為2的冪,使用位與運算代替取模運算,減少運算消耗;而HashTable的hash算法首先使得hash值小于整型數最大值,再通過取模進行散射運算

LinkedHashMap

  • LinkedHashMap的元素存取過程基本與HashMap基本類似,只是在細節實現上稍有不同。當然,這是由LinkedHashMap本身的特性所決定的,因為它額外維護了一個雙向鏈表用于保持迭代順序。此外,LinkedHashMap可以很好的支持LRU算法。HashMap和雙向鏈表合二為一即是LinkedHashMap

WeakHashMap

  • WeakHashMap 也是一個散列表,它存儲的內容也是鍵值對(key-value)映射,而且鍵和值都可以是 null
  • WeakHashMap的鍵是“弱鍵”。在 WeakHashMap 中,當某個 key 不再被強引用使用時,會被從WeakHashMap中被 JVM 自動移除,然后它對應的鍵值對也會被從WeakHashMap中移除。?JAVA引用類型和ThreadLocal

ConcurrentHashMap(1.8JDK)

  • ConcurrentHashMap 是 HashMap 的多線程安全版本。它使用了細粒度鎖 和 cas 提高了在多線程環境的安全性和高并發
  • 底層數據結構是 數組 + 鏈表/紅黑樹(后面專門寫一篇介紹)

ConcurrentSkipListMap 了解一波

  • ConcurrentSkipListMap 則是基于跳躍鏈表的實現的 map,使用了 cas 技術實現線程安全性,高并發
  • ConcurrentSkipListMap 相比 ConcurrentHashMap 的優點
    • ConcurrentSkipListMap 的key是有序的。
    • ConcurrentSkipListMap 支持更高的并發。ConcurrentSkipListMap的存取時間是log(N),和線程數幾乎無關。也就是說在數據量一定的情況下,并發的線程越多,ConcurrentSkipListMap 越能體現出它的優勢

NavigableMap 和 ConcurrentNavigableMap 操作 key 值的范圍區間

  • TreeMap 實現了 NavigableMap 。ConcurrentNavigableMap 高并發線程安全版的 TreeMap
  • NavigableMap 提供了針對給定搜索目標返回最接近匹配項的導航方法。直接看API
  1. K lowerKey(K key)  // 找到第一個比指定的key小的值 
  2. K floorKey(K key)  // 找到第一個比指定的key小于或等于的key 
  3. K ceilingKey(K key) // 找到第一個大于或等于指定key的值 
  4. K higherKey(K key) // 找到第一個大于指定key的值 
  5. Map.Entry<K,V> firstEntry() // 獲取最小值 
  6. Map.Entry<K,V> lastEntry() // 獲取最大值 
  7. Map.Entry<K,V> pollFirstEntry() // 刪除最小的元素 
  8. Map.Entry<K,V> pollLastEntry() // 刪除最大的元素 
  9. NavigableMap<K,V> descendingMap() //返回一個倒序的Map  
  10. // 返回值小于 toKey 的 NavigableMap 
  11. NavigableMap<K,V> headMap(K toKey, boolean inclusive) 
  12. // 返回值大于 fromKey 的 NavigableMap 
  13. NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) 
  14. // 返回值小于 toKey 大于 的 fromKey NavigableMap 
  15. NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey,   boolean toInclusive) 

5.Set(集合)

  • Set特點:元素無放入順序,元素不可重復,如果加入重復元素,會保留最先加入的對象。存取速度快

Set 的幾種實現子類和各自特點

  • TreeSet:底層數據結構采用二叉樹來實現,元素唯一且已經排好序;唯一性同樣需要重寫 hashCode 和 equals()方法,二叉樹結構保證了元素的有序
    • 根據構造方法不同,分為自然排序(無參構造)和比較器排序(有參構造),自然排序要求元素必須實現Compareable接口,并重寫里面的compareTo()方法
  • HashSet:是哈希表實現的,HashSet中的數據是無序的,可以放入 null,但只能放入一個null,兩者中的值都不能重復,就如數據庫中唯一約束
    • HashSet 是基于 HashMap 算法實現的,其性能通常都優于TreeSet
    • 為快速查找而設計的Set,我們通常都會用到HashSet,若需要排序的功能時,才使用TreeSet
  • LinkedHashSet:底層數據結構采用鏈表和哈希表共同實現,鏈表保證了元素的順序與存儲順序一致,哈希表保證了元素的唯一性,效率高。但線程不安全

ConcurrentSkipListSet

  • 基于 ConcurrentSkipListMap 實現

CopyOnWriteArraySet

  • 基于 CopyOnWriteArrayList 實現

BitSet

  • BitSet是位操作的對象,值只有 0 或 1 即false和true,內部維護了一個long數組,初始只有一個long,所以BitSet最小的size是64,當隨著存儲的元素越來越多,BitSet內部會動態擴充,最終內部是由N個long來存儲
  • 如統計40億個數據中沒有出現的數據,將40億個不同數據進行排序等。\
  • 現在有1千萬個隨機數,隨機數的范圍在1到1億之間?,F在要求寫出一種算法,將1到1億之間沒有在隨機數中的數求出來
  1. void and(BitSet set) // 兩個BitSet 做與操作,結果并存入當前 BitSet 
  2. void andNot(BitSet set) //  兩個BitSet 與非操作 
  3. void flip(int index) // 反轉某一個指定 index  
  4. boolean intersects(BitSet bitSet) // 是否有交集 
  5. int cardinality() //返回 true/1 的個數 
  6. void clear() // 重置 
  7. void clear(int startIndex, int endIndex) // startIndex~endIndex 重置 
  8. int nextSetBit(int startIndex) //檢索在startIndex之后出現為1的第一位的索引 
  9. int nextClearBit(int startIndex) //檢索在startIndex之后出現為0的第一位的索引 

6.Queue(隊列)

  • Queue的概念 隊列是一種特殊的線性表,只允許元素從隊列一端入隊,而另一端出隊(獲取元素),就像我們平時排隊結算一樣(懂文明講禮貌不插隊)。Queue 的數據結構和 List 一樣,可以基于數組,鏈表實現,隊列通常都是一端進(offer),另一端出(poll),有序性

PriorityQueue

  • PriorityQueue是按優先級排序的隊列,也就是說 vip 可以插隊。優先隊列要求使用 Java Comparable 和 Comparator 接口給對象排序,并且在排序時會按照優先級處理其中的元素
  • PriorityBlockingQueue 是線程安全的PriorityQueue

BlockingQueue

  • BlockingQueue很好的解決了多線程中,如何高效安全“傳輸”數據的問題。通過這些高效并且線程安全的隊列類,為我們快速搭建高質量的多線程程序帶來極大的便利。常用于線程的任務隊列

DelayQueue

  • DelayQueue是一個沒有邊界BlockingQueue實現,加入元素必須實現Delayed接口。當生產者線程調用put之類的方法加入元素時,會觸發 Delayed 接口中的compareTo方法進行排序
  • 消費者線程查看隊列頭部的元素,注意是查看不是取出。然后調用元素的getDelay方法,如果此方法返回的值小0或者等于0,則消費者線程會從隊列中取出此元素,并進行處理。如果getDelay方法返回的值大于0,則消費者線程阻塞到第一元素過期

Queue 的 API

  1. boolean add(E e); //加入隊列尾部 
  2. boolean offer(E e); // 加入隊列尾部,并返回結果 
  3. E remove(); //移除頭部元素 
  4. E poll();  // 獲取頭部元素,并移除 
  5. E element(); // 獲取頭部元素,不存在則報錯 
  6. E peek(); // 獲取頭部元素,不移除 

7.Deque(雙向隊列)

  • Deque接口代表一個"雙端隊列",雙端隊列可以同時從兩端來添加、刪除元素,因此Deque的實現類既可以當成隊列使用、也可以當成棧使用
  • Deque 的子類 LinkedList,ArrayDeque,LinkedBlockingDeque

Deque的 API

  1. void addFirst(E e); //加入頭部 
  2. void addLast(E e);  //加入尾部 
  3. boolean offerFirst(E e); //加入頭部,并返回結果 
  4. boolean offerLast(E e); //加入尾部,并返回結果 
  5. E removeFirst(); // 移除第一個元素 
  6. E removeLast(); // 移除最后一個元素 
  7. E getFirst(); //獲取第一個元素,不存在則報錯 
  8. E getLast();  //獲取最后一個元素,不存在則報錯 
  9. E pollFirst(); //獲取第一個元素,并移除 
  10. E pollLast(); //獲取最后一個元素,并移除 
  11. E peekFirst(); //獲取第一個元素 
  12. E peekLast(); // 獲取最后一個元素 
  13. void push(E e); //加入頭部 
  14. E pop(); //彈出頭部元素 

參考文章 

java集合超詳解

 

責任編輯:武曉燕 來源: 潛行前行
相關推薦

2021-06-28 07:44:11

面試 DelayQueue任務調度

2021-05-23 16:03:42

LinkedBlock面試阻塞隊列

2021-05-17 07:36:54

ArrayBlocki面試集合

2021-05-29 12:24:29

Synchronous公平模式

2021-06-02 21:31:39

Synchronous非公平模式

2020-11-16 10:19:33

Java

2020-07-28 08:59:22

JavahreadLocal面試

2018-04-19 14:11:50

2018-08-21 13:25:01

編程語言Java面試題

2012-08-14 10:31:28

面試

2012-08-21 09:20:57

Yahoo

2012-08-09 10:02:08

面試Google

2012-11-05 10:01:32

2022-03-28 09:31:58

for循環語句

2020-10-20 10:17:20

Java泛型Type

2018-04-02 08:28:45

Java面試存儲

2020-11-13 07:22:46

Java基礎While

2022-01-27 09:35:45

whiledo-while循環Java基礎

2015-05-11 14:02:21

JavaJava集合面試問題答案

2012-05-25 10:15:06

Java程序員面試題
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国内精品久久久久 | 国产激情 | 麻豆国产一区二区三区四区 | 久久免费大片 | 青青久草| 欧美成人一级视频 | 国产综合在线视频 | 国产欧美在线视频 | 亚洲精品不卡 | 99精品国产一区二区青青牛奶 | 国产精品精品视频一区二区三区 | 中文字幕在线视频免费观看 | 麻豆av片| 国产三级精品三级在线观看四季网 | 精品国产乱码久久久久久88av | 18av在线播放| 中文字幕日韩欧美一区二区三区 | 欧美日在线 | 国产亚洲一区在线 | 中文字幕精品一区二区三区精品 | 亚洲欧美在线视频 | 精品久久久久久久久久久久 | 久久精品国产久精国产 | 日韩成人中文字幕 | 亚洲综合视频一区 | 一区二区三区四区国产精品 | 免费在线观看毛片 | 91精品国产综合久久婷婷香蕉 | 亚洲精品粉嫩美女一区 | 日韩av在线中文字幕 | 成人福利网 | 99国产精品久久久 | 国产午夜精品视频 | 久久麻豆精品 | 四虎国产 | 中文字幕一区在线 | 日韩毛片免费视频 | 亚洲高清在线 | 国产精品自拍视频网站 | 日韩在线视频网址 | 欧美婷婷|