亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java集合---ArrayList的實現原理

2019-11-06 06:14:43
字體:
來源:轉載
供稿:網友

學習java的同學注意了!?。?nbsp;學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986  我們一起學Java!

目錄:

      一、 ArrayList概述

      二、 ArrayList的實現

                  1) 私有屬性

                 2) 構造方法

                 3) 元素存儲

                 4) 元素讀取

                 5) 元素刪除                 6) 調整數組容量                 7)轉為靜態數組toArray

      總結

 

一、 ArrayList概述:  

ArrayList是基于數組實現的,是一個動態數組,其容量能自動增長,類似于C語言中的動態申請內存,動態增長內存。

 

    ArrayList不是線程安全的,只能用在單線程環境下,多線程環境下可以考慮用Collections.synchronizedList(List l)函數返回一個線程安全的ArrayList類,也可以使用concurrent并發包下的CopyOnWriteArrayList類。

 

    ArrayList實現了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實現了Randomaccess接口,支持快速隨機訪問,實際上就是通過下標序號進行快速訪問,實現了Cloneable接口,能被克隆。

   每個ArrayList實例都有一個容量,該容量是指用來存儲列表元素的數組的大小。它總是至少等于列表的大小。隨著向ArrayList中不斷添加元素,其容量也自動增長。自動增長會帶來數據向新數組的重新拷貝,因此,如果可預知數據量的多少,可在構造ArrayList時指定其容量。在添加大量元素前,應用程序也可以使用ensureCapacity操作來增加ArrayList實例的容量,這可以減少遞增式再分配的數量。    注意,此實現不是同步的。如果多個線程同時訪問一個ArrayList實例,而其中至少一個線程從結構上修改了列表,那么它必須保持外部同步。

 

二、 ArrayList的實現:

   對于ArrayList而言,它實現List接口、底層使用數組保存所有元素。其操作基本上是對數組的操作。下面我們來分析ArrayList的源代碼:

   1) 私有屬性:

   ArrayList定義只定義類兩個私有屬性:

 

復制代碼
    /**       * The array buffer into which the elements of the ArrayList are stored.       * The capacity of the ArrayList is the length of this array buffer.       */       PRivate transient Object[] elementData;          /**       * The size of the ArrayList (the number of elements it contains).       *       * @serial       */       private int size;復制代碼

 很容易理解,elementData存儲ArrayList內的元素,size表示它包含的元素的數量。

有個關鍵字需要解釋:transient。  

  Java的serialization提供了一種持久化對象實例的機制。當持久化對象時,可能有一個特殊的對象數據成員,我們不想用serialization機制來保存它。為了在一個特定對象的一個域上關閉serialization,可以在這個域前加上關鍵字transient。

有點抽象,看個例子應該能明白。

復制代碼
public class UserInfo implements Serializable {       private static final long serialVersionUID = 996890129747019948L;       private String name;       private transient String psw;          public UserInfo(String name, String psw) {           this.name = name;           this.psw = psw;       }          public String toString() {           return "name=" + name + ", psw=" + psw;       }   }      public class TestTransient {       public static void main(String[] args) {           UserInfo userInfo = new UserInfo("張三", "123456");           System.out.println(userInfo);           try {               // 序列化,被設置為transient的屬性沒有被序列化               ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(                       "UserInfo.out"));               o.writeObject(userInfo);               o.close();           } catch (Exception e) {               // TODO: handle exception               e.printStackTrace();           }           try {               // 重新讀取內容               ObjectInputStream in = new ObjectInputStream(new FileInputStream(                       "UserInfo.out"));               UserInfo readUserInfo = (UserInfo) in.readObject();               //讀取后psw的內容為null               System.out.println(readUserInfo.toString());           } catch (Exception e) {               // TODO: handle exception               e.printStackTrace();           }       }   }復制代碼

被標記為transient的屬性在對象被序列化的時候不會被保存。

接著回到ArrayList的分析中......

2) 構造方法:    ArrayList提供了三種方式的構造器,可以構造一個默認初始容量為10的空列表、構造一個指定初始容量的空列表以及構造一個包含指定collection的元素的列表,這些元素按照該collection的迭代器返回它們的順序排列的。

 

復制代碼
    // ArrayList帶容量大小的構造函數。        public ArrayList(int initialCapacity) {            super();            if (initialCapacity < 0)                throw new IllegalArgumentException("Illegal Capacity: "+                                                   initialCapacity);            // 新建一個數組            this.elementData = new Object[initialCapacity];        }           // ArrayList無參構造函數。默認容量是10。        public ArrayList() {            this(10);        }           // 創建一個包含collection的ArrayList        public ArrayList(Collection<? extends E> c) {            elementData = c.toArray();            size = elementData.length;            if (elementData.getClass() != Object[].class)                elementData = Arrays.copyOf(elementData, size, Object[].class);        }復制代碼

 

3) 元素存儲:

ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)、addAll(int index, Collection<? extends E> c)這些添加元素的方法。下面我們一一講解:

 

復制代碼
20 // 用指定的元素替代此列表中指定位置上的元素,并返回以前位于該位置上的元素。  21 public E set(int index, E element) {  22    RangeCheck(index);  23  24    E oldValue = (E) elementData[index];  25    elementData[index] = element;  26    return oldValue;  27 }    28 // 將指定的元素添加到此列表的尾部。  29 public boolean add(E e) {  30    ensureCapacity(size + 1);   31    elementData[size++] = e;  32    return true;  33 }    34 // 將指定的元素插入此列表中的指定位置。  35 // 如果當前位置有元素,則向右移動當前位于該位置的元素以及所有后續元素(將其索引加1)。  36 public void add(int index, E element) {  37    if (index > size || index < 0)  38        throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);  39    // 如果數組長度不足,將進行擴容。  40    ensureCapacity(size+1);  // Increments modCount!!  41    // 將 elementData中從Index位置開始、長度為size-index的元素,  42    // 拷貝到從下標為index+1位置開始的新的elementData數組中。  43    // 即將當前位于該位置的元素以及所有后續元素右移一個位置。  44    System.arraycopy(elementData, index, elementData, index + 1, size - index);  45    elementData[index] = element;  46    size++;  47 }    48 // 按照指定collection的迭代器所返回的元素順序,將該collection中的所有元素添加到此列表的尾部。  49 public boolean addAll(Collection<? extends E> c) {  50    Object[] a = c.toArray();  51    int numNew = a.length;  52    ensureCapacity(size + numNew);  // Increments modCount  53    System.arraycopy(a, 0, elementData, size, numNew);  54    size += numNew;  55    return numNew != 0;  56 }    57 // 從指定的位置開始,將指定collection中的所有元素插入到此列表中。  58 public boolean addAll(int index, Collection<? extends E> c) {  59    if (index > size || index < 0)  60        throw new IndexOutOfBoundsException(  61            "Index: " + index + ", Size: " + size);  62  63    Object[] a = c.toArray();  64    int numNew = a.length;  65    ensureCapacity(size + numNew);  // Increments modCount  66  67    int numMoved = size - index;  68    if (numMoved > 0)  69        System.arraycopy(elementData, index, elementData, index + numNew, numMoved);  70  71    System.arraycopy(a, 0, elementData, index, numNew);  72    size += numNew;  73    return numNew != 0;     }  復制代碼

 

書上都說ArrayList是基于數組實現的,屬性中也看到了數組,具體是怎么實現的呢?比如就這個添加元素的方法,如果數組大,則在將某個位置的值設置為指定元素即可,如果數組容量不夠了呢?

    看到add(E e)中先調用了ensureCapacity(size+1)方法,之后將元素的索引賦給elementData[size],而后size自增。例如初次添加時,size為0,add將elementData[0]賦值為e,然后size設置為1(類似執行以下兩條語句elementData[0]=e;size=1)。將元素的索引賦給elementData[size]不是會出現數組越界的情況嗎?這里關鍵就在ensureCapacity(size+1)中了。

 

 4) 元素讀取:

 

 // 返回此列表中指定位置上的元素。   public E get(int index) {      RangeCheck(index);        return (E) elementData[index];    }

 

5) 元素刪除:

 

ArrayList提供了根據下標或者指定對象兩種方式的刪除功能。如下:

 romove(int index):

復制代碼
 1 // 移除此列表中指定位置上的元素。   2  public E remove(int index) {   3     RangeCheck(index);   4    5     modCount++;   6     E oldValue = (E) elementData[index];   7    8     int numMoved = size - index - 1;   9     if (numMoved > 0)  10         System.arraycopy(elementData, index+1, elementData, index, numMoved);  11     elementData[--size] = null; // Let gc do its work  12   13     return oldValue;  14  }復制代碼

首先是檢查范圍,修改modCount,保留將要被移除的元素,將移除位置之后的元素向前挪動一個位置,將list末尾元素置空(null),返回被移除的元素。

remove(Object o)

 

復制代碼
 1  // 移除此列表中首次出現的指定元素(如果存在)。這是應為ArrayList中允許存放重復的元素。   2  public boolean remove(Object o) {   3     // 由于ArrayList中允許存放null,因此下面通過兩種情況來分別處理。   4     if (o == null) {   5         for (int index = 0; index < size; index++)   6             if (elementData[index] == null) {   7                 // 類似remove(int index),移除列表中指定位置上的元素。   8                 fastRemove(index);   9                 return true;  10             }  11     } else {  12         for (int index = 0; index < size; index++)  13             if (o.equals(elementData[index])) {  14                 fastRemove(index);  15                 return true;  16             }  17         }  18         return false;  19     } 20 } 復制代碼

首先通過代碼可以看到,當移除成功后返回true,否則返回false。remove(Object o)中通過遍歷element尋找是否存在傳入對象,一旦找到就調用fastRemove移除對象。為什么找到了元素就知道了index,不通過remove(index)來移除元素呢?因為fastRemove跳過了判斷邊界的處理,因為找到元素就相當于確定了index不會超過邊界,而且fastRemove并不返回被移除的元素。下面是fastRemove的代碼,基本和remove(index)一致。

復制代碼
1 private void fastRemove(int index) {  2          modCount++;  3          int numMoved = size - index - 1;  4          if (numMoved > 0)  5              System.arraycopy(elementData, index+1, elementData, index,  6                               numMoved);  7          elementData[--size] = null; // Let gc do its work  8  }復制代碼

removeRange(int fromIndex,int toIndex)

復制代碼
 1 protected void removeRange(int fromIndex, int toIndex) {   2      modCount++;   3      int numMoved = size - toIndex;   4          System.arraycopy(elementData, toIndex, elementData, fromIndex,   5                           numMoved);   6     7      // Let gc do its work   8      int newSize = size - (toIndex-fromIndex);   9      while (size != newSize)  10          elementData[--size] = null;  11 }  復制代碼

執行過程是將elementData從toIndex位置開始的元素向前移動到fromIndex,然后將toIndex位置之后的元素全部置空順便修改size。

    這個方法是protected,及受保護的方法,為什么這個方法被定義為protected呢?

    這是一個解釋,但是可能不容易看明白。http://stackoverflow.com/questions/2289183/why-is-javas-abstractlists-removerange-method-protected

    先看下面這個例子

 

         ArrayList<Integer> ints = new ArrayList<Integer>(Arrays.asList(0, 1, 2,                   3, 4, 5, 6));           // fromIndex low endpoint (inclusive) of the subList           // toIndex high endpoint (exclusive) of the subList          ints.subList(2, 4).clear();           System.out.println(ints);  

 

輸出結果是[0, 1, 4, 5, 6],結果是不是像調用了removeRange(int fromIndex,int toIndex)!哈哈哈,就是這樣的。但是為什么效果相同呢?是不是調用了removeRange(int fromIndex,int toIndex)呢?

 

6) 調整數組容量ensureCapacity: 

   從上面介紹的向ArrayList中存儲元素的代碼中,我們看到,每當向數組中添加元素時,都要去檢查添加后元素的個數是否會超出當前數組的長度,如果超出,數組將會進行擴容,以滿足添加數據的需求。數組擴容通過一個公開的方法ensureCapacity(int minCapacity)來實現。在實際添加大量元素前,我也可以使用ensureCapacity來手動增加ArrayList實例的容量,以減少遞增式再分配的數量。

 

復制代碼
public void ensureCapacity(int minCapacity) {      modCount++;      int oldCapacity = elementData.length;      if (minCapacity > oldCapacity) {          Object oldData[] = elementData;          int newCapacity = (oldCapacity * 3)/2 + 1;  //增加50%+1            if (newCapacity < minCapacity)                  newCapacity = minCapacity;        // minCapacity is usually close to size, so this is a win:        elementData = Arrays.copyOf(elementData, newCapacity);      }   }復制代碼

 

 從上述代碼中可以看出,數組進行擴容時,會將老數組中的元素重新拷貝一份到新的數組中,每次數組容量的增長大約是其原容量的1.5倍。這種操作的代價是很高的,因此在實際使用時,我們應該盡量避免數組容量的擴張。當我們可預知要保存的元素的多少時,要在構造ArrayList實例時,就指定其容量,以避免數組擴容的發生?;蛘吒鶕嶋H需求,通過調用ensureCapacity方法來手動增加ArrayList實例的容量。

Object oldData[] = elementData;//為什么要用到oldData[]乍一看來后面并沒有用到關于oldData, 這句話顯得多此一舉!但是這是一個牽涉到內存管理的類, 所以要了解內部的問題。 而且為什么這一句還在if的內部,這跟elementData = Arrays.copyOf(elementData, newCapacity); 這句是有關系的,下面這句Arrays.copyOf的實現時新創建了newCapacity大小的內存,然后把老的elementData放入。好像也沒有用到oldData,有什么問題呢。問題就在于舊的內存的引用是elementData, elementData指向了新的內存塊,如果有一個局部變量oldData變量引用舊的內存塊的話,在copy的過程中就會比較安全,因為這樣證明這塊老的內存依然有引用,分配內存的時候就不會被侵占掉,然后copy完成后這個局部變量的生命期也過去了,然后釋放才是安全的。不然在copy的的時候萬一新的內存或其他線程的分配內存侵占了這塊老的內存,而copy還沒有結束,這將是個嚴重的事情。

 

  關于ArrayList和Vector區別如下:

ArrayList在內存不夠時默認是擴展50% + 1個,Vector是默認擴展1倍。Vector提供indexOf(obj, start)接口,ArrayList沒有。Vector屬于線程安全級別的,但是大多數情況下不使用Vector,因為線程安全需要更大的系統開銷。

 

 ArrayList還給我們提供了將底層數組的容量調整為當前列表保存的實際元素的大小的功能。它可以通過trimToSize方法來實現。代碼如下:

 

復制代碼
127 public void trimToSize() {  128    modCount++;  129    int oldCapacity = elementData.length;  130    if (size < oldCapacity) {  131        elementData = Arrays.copyOf(elementData, size);  132    }      }復制代碼

 由于elementData的長度會被拓展,size標記的是其中包含的元素的個數。所以會出現size很小但elementData.length很大的情況,將出現空間的浪費。trimToSize將返回一個新的數組給elementData,元素內容保持不變,length和size相同,節省空間。

 

7)轉為靜態數組toArray

 4、注意ArrayList的兩個轉化為靜態數組的toArray方法。

    第一個, 調用Arrays.copyOf將返回一個數組,數組內容是size個elementData的元素,即拷貝elementData從0至size-1位置的元素到新數組并返回。

 

public Object[] toArray() {           return Arrays.copyOf(elementData, size);   } 

 

    第二個,如果傳入數組的長度小于size,返回一個新的數組,大小為size,類型與傳入數組相同。所傳入數組長度與size相等,則將elementData復制到傳入數組中并返回傳入的數組。若傳入數組長度大于size,除了復制elementData外,還將把返回數組的第size個元素置為空。

 

復制代碼
public <T> T[] toArray(T[] a) {        if (a.length < size)            // Make a new array of a's runtime type, but my contents:            return (T[]) Arrays.copyOf(elementData, size, a.getClass());    System.arraycopy(elementData, 0, a, 0, size);        if (a.length > size)            a[size] = null;        return a;    } 復制代碼

 

Fail-Fast機制: ArrayList也采用了快速失敗的機制,通過記錄modCount參數來實現。在面對并發的修改時,迭代器很快就會完全失敗,而不是冒著在將來某個不確定時間發生任意不確定行為的風險。具體介紹請參考這篇文章深入Java集合學習系列:HashMap的實現原理 中的Fail-Fast機制。

 

總結:

關于ArrayList的源碼,給出幾點比較重要的總結:

    1、注意其三個不同的構造方法。無參構造方法構造的ArrayList的容量默認為10,帶有Collection參數的構造方法,將Collection轉化為數組賦給ArrayList的實現數組elementData。

    2、注意擴充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1個,也可能是一組)時,都要調用該方法來確保足夠的容量。當容量不足以容納當前的元素個數時,就設置新的容量為舊的容量的1.5倍加1,如果設置后的新容量還不夠,則直接新容量設置為傳入的參數(也就是所需的容量),而后用Arrays.copyof()方法將元素拷貝到新的數組(詳見下面的第3點)。從中可以看出,當容量不夠時,每次增加元素,都要將原來的元素拷貝到一個新的數組中,非常之耗時,也因此建議在事先能確定元素數量的情況下,才使用ArrayList,否則建議使用LinkedList。

    3、ArrayList的實現中大量地調用了Arrays.copyof()和System.arraycopy()方法。我們有必要對這兩個方法的實現做下深入的了解。

    首先來看Arrays.copyof()方法。它有很多個重載的方法,但實現思路都是一樣的,我們來看泛型版本的源碼:

public static <T> T[] copyOf(T[] original, int newLength) {      return (T[]) copyOf(original, newLength, original.getClass());  }

很明顯調用了另一個copyof方法,該方法有三個參數,最后一個參數指明要轉換的數據的類型,其源碼如下:

復制代碼
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {      T[] copy = ((Object)newType == (Object)Object[].class)          ? (T[]) new Object[newLength]          : (T[]) Array.newInstance(newType.getComponentType(), newLength);      System.arraycopy(original, 0, copy, 0,                       Math.min(original.length, newLength));      return copy;  } 復制代碼

這里可以很明顯地看出,該方法實際上是在其內部又創建了一個長度為newlength的數組,調用System.arraycopy()方法,將原來數組中的元素復制到了新的數組中。

    下面來看System.arraycopy()方法。該方法被標記了native,調用了系統的C/C++代碼,在JDK中是看不到的,但在openJDK中可以看到其源碼。該函數實際上最終調用了C語言的memmove()函數,因此它可以保證同一個數組內元素的正確復制和移動,比一般的復制方法的實現效率要高很多,很適合用來批量處理數組。Java強烈推薦在復制大量數組元素時用該方法,以取得更高的效率。

 

4、ArrayList基于數組實現,可以通過下標索引直接查找到指定位置的元素,因此查找效率高,但每次插入或刪除元素,就要大量地移動元素,插入刪除元素的效率低。

5、在查找給定元素索引值等的方法中,源碼都將該元素的值分為null和不為null兩種情況處理,ArrayList中允許元素為null。

學習Java的同學注意了?。?! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986  我們一起學Java!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品乱码久久久久久金桔影视| 欧洲精品久久久| 97香蕉超级碰碰久久免费的优势| 亚洲国产精彩中文乱码av在线播放| 26uuu另类亚洲欧美日本老年| 高潮白浆女日韩av免费看| 欧美大荫蒂xxx| 日韩视频在线一区| 91天堂在线视频| 午夜精品免费视频| 国产精品电影一区| 98视频在线噜噜噜国产| 欧美日韩国产麻豆| 亚洲精品中文字幕女同| yw.139尤物在线精品视频| 日韩av在线网站| 91免费看国产| 亚洲色图35p| 亚洲色图美腿丝袜| 日本成人在线视频网址| 在线日韩精品视频| 川上优av一区二区线观看| 91免费高清视频| 精品国产区一区二区三区在线观看| 1769国内精品视频在线播放| 欧美精品亚州精品| 欧美亚洲视频在线看网址| 日韩中文字幕第一页| 亚洲成人黄色在线| 欧美日韩免费一区| 国产97色在线| 中文字幕在线看视频国产欧美在线看完整| 欧美日韩国产一区中文午夜| 91国产高清在线| 国产成人精品视频在线观看| 国产精品黄色影片导航在线观看| 啪一啪鲁一鲁2019在线视频| 伊人久久久久久久久久久| 欧美成人黄色小视频| 亚洲国产精品人久久电影| 亚洲美女福利视频网站| 久久伊人91精品综合网站| 日韩电影在线观看中文字幕| 久久久久一本一区二区青青蜜月| 久久久久久久久91| 精品久久久久久中文字幕一区奶水| 欧美在线激情网| 亚洲风情亚aⅴ在线发布| 国产成人免费av| 国产精品aaa| 亚洲黄色av女优在线观看| 中文字幕日韩有码| 成人黄色在线播放| 精品自在线视频| 中文字幕免费精品一区| 欧美日韩国产在线| 久久久久久伊人| 欧美激情第99页| 国产综合在线视频| 国语自产精品视频在免费| 成人免费视频网| 亚洲一区二区久久久久久| 91精品在线观| 亚洲欧美日韩一区二区三区在线| 成人久久18免费网站图片| xxxxx成人.com| 超碰91人人草人人干| 欧美精品18videos性欧美| 一区二区三区四区在线观看视频| 亚洲国产精品系列| 亚洲男人天堂手机在线| 日本中文字幕久久看| 国产成人小视频在线观看| 91精品中国老女人| 亚洲国产欧美一区二区三区久久| 日韩电影中文字幕在线观看| 欧美黑人国产人伦爽爽爽| 激情成人在线视频| 日韩精品在线影院| 亚洲男人的天堂在线播放| 成人在线视频福利| 精品视频在线观看日韩| 欧美视频专区一二在线观看| 亚洲欧美在线一区| 日韩视频免费观看| 日韩电影大片中文字幕| xvideos成人免费中文版| 九九精品视频在线观看| 久久久亚洲影院你懂的| 欧美国产欧美亚洲国产日韩mv天天看完整| 久久99青青精品免费观看| 欧美激情一级精品国产| 青青草国产精品一区二区| 97久久精品在线| 一区二区在线视频播放| 亚洲激情成人网| 亚洲精品视频免费在线观看| 国产精品精品视频一区二区三区| 国产成人精品免高潮在线观看| 日韩专区中文字幕| 欧美激情视频给我| 久热爱精品视频线路一| 国产精品69精品一区二区三区| 91精品国产网站| 欧美成人午夜激情| www.久久草.com| 国产日韩精品一区二区| 国产精品天天狠天天看| 少妇久久久久久| 最近2019年日本中文免费字幕| 亚洲国产精品久久久久秋霞蜜臀| 欧美寡妇偷汉性猛交| 日本高清不卡的在线| 欧美在线观看网址综合| 欧美不卡视频一区发布| 久久人人爽人人爽人人片av高请| 欧美在线视频网| 欧美色视频日本高清在线观看| 久久精品中文字幕电影| 国产精品毛片a∨一区二区三区|国| 久久精品99久久久香蕉| 欧美国产日韩一区二区在线观看| 最近2019年中文视频免费在线观看| 国产午夜精品视频免费不卡69堂| 日本不卡高字幕在线2019| 俺去了亚洲欧美日韩| 正在播放亚洲1区| 国产精品久久久999| 国产香蕉精品视频一区二区三区| 中国china体内裑精亚洲片| 国产精品极品尤物在线观看| 亚洲第一福利网| 国产午夜精品美女视频明星a级| 北条麻妃99精品青青久久| 亚洲人成在线观看| 亚洲a∨日韩av高清在线观看| 成人国产精品av| 久久影院免费观看| 国产精品海角社区在线观看| 欧美精品在线免费| 日韩激情av在线免费观看| 久久久精品免费视频| 狠狠综合久久av一区二区小说| 欧美在线观看视频| 日韩在线视频中文字幕| 国产最新精品视频| 8x海外华人永久免费日韩内陆视频| 精品久久久久久中文字幕大豆网| 成人福利网站在线观看| 亚洲精品美女久久| 高清一区二区三区日本久| 26uuu国产精品视频| 国产视频在线观看一区二区| 久久香蕉频线观| 亚洲精品99久久久久| 国内精品久久久久影院 日本资源| 欧美丝袜美女中出在线| 免费99精品国产自在在线| 久久成年人免费电影| 久久成人这里只有精品| 国产精品日韩欧美大师| 91影院在线免费观看视频| 久久视频免费观看| 欧美性20hd另类|