日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > java-對象管理-集合

java-對象管理-集合

來源:程序員人生   發布時間:2016-06-07 16:06:48 閱讀次數:2811次

在實際的項目開發中會有很多的對象,如何高效、方便地管理對象,成為影響程序性能與可保護性的重要環節。Java 提供了集合框架來解決此類問題,線性表、鏈表、哈希表等是經常使用的數據結構,在進行 Java 開發時,JDK 已為我們提供了1系列相應的類來實現基本的數據結構,所有類都在 java.util 這個包里。

Collection ├List │├LinkedList │├ArrayList │└Vector │ └StackSet Map ├Hashtable ├HashMap └WeakHashMap

Collection 接口
Collection 是最基本的集合接口,1個 Collection 代表1組 Object,即 Collection 的元素(Elements)。1些 Collection 允許相同的元素、支持對元素進行排序,另外一些則不行。JDK 不提供直接繼承自 Collection 的類,JDK 提供的類都是繼承自 Collection 的子接口,如 List 和 Set。所有實現 Collection 接口的類都必須提供兩個標準的構造函數,無參數的構造函數用于創建1個空的 Collection,有1個 Collection 參數的構造函數用于創建1個新的 Collection,這個新的 Collection 與傳入的 Collection 有相同的元素,后1個構造函數允許用戶復制1個 Collection。
如何遍歷 Collection 中的每個元素?
不論 Collection 的實際類型如何,它都支持1個 iterator() 的方法,該方法返回1個迭代子,使用該迭代子便可逐1訪問 Collection 中每個元素。典型的用法以下:
Iterator it = collection.iterator(); // 取得1個迭代子
while(it.hasNext()){
Object obj = it.next(); // 得到下1個元素
}
Collection 接口派生的兩個接口是 List 和 Set。
Collection 接口提供的主要方法:
boolean add(Object o) 添加對象到集合;
boolean remove(Object o) 刪除指定的對象;
int size() 返回當前集合中元素的數量;
boolean contains(Object o) 查找集合中是不是有指定的對象;
boolean isEmpty() 判斷集合是不是為空;
Iterator iterator() 返回1個迭代器;
boolean containsAll(Collection c) 查找集合中是不是有集合 C 中的元素;
boolean addAll(Collection c) 將集合 C 中所有的元素添加給該集合;
void clear() 刪除集合中所有元素;
void removeAll(Collection c) 從集合中刪除 C 集合中也有的元素;
void retainAll(Collection c) 從集合中刪除集合 C 中不包括的元素。
List 接口
List 是有序的 Collection,使用此接口能夠精確的控制每一個元素插入的位置。用戶能夠使用索引(元素在 List 中的位置,類似于數組下標)來訪問 List 中的元素,這類似于 Java 的數組。和下文要提到的 Set 不同,List 允許有相同的元素。
除具有 Collection 接口必備的 iterator() 方法外,List 還提供1個 listIterator() 方法,返回1個 ListIterator 接口。和標準的 Iterator 接口相比,ListIterator 多了1些 add() 之類的方法,允許添加、刪除、設定元素、向前或向后遍歷等功能。實現 List 接口的經常使用類有 LinkedList,ArrayList,Vector 和 Stack 等。
List 接口提供的主要方法:
void add(int index,Object element) 在指定位置上添加1個對象;
boolean addAll(int index,Collection c) 將集合 C 的元素添加到指定的位置;
Object get(int index) 返回 List 中指定位置的元素;
int indexOf(Object o) 返回第1個出現元素 O 的位置;
Object removeint(int index) 刪除指定位置的元素;
Object set(int index,Object element) 用元素 element 取代位置 index 上的元素, 返回被取代的元素。
Map 接口
Map 沒有繼承 Collection 接口。Map 提供 Key 到 Value 的映照,1個 Map 中不能包括相同的 Key,每一個 Key 只能映照1個 Value。Map 接口提供 3 種集合的視圖,Map 的內容可以被當作1組 Key 集合,1組 Value 集合,或1組 Key-Value 映照。
Map 提供的主要方法:
boolean equals(Object o) 比較對象;
boolean remove(Object o) 刪除1個對象;
put(Object key,Object value) 添加 key 和 value。
RandomAccess 接口
RandomAccess 接口是1個標志接口,本身并沒有提供任何方法,任務凡是通過調用 RandomAccess 接口的對象都可以認為是支持快速隨機訪問的對象。此接口的主要目的是標識那些可支持快速隨機訪問的 List 實現。任何1個基于數組的 List 實現都實現了 RaodomAccess 接口,而基于鏈表的實現則都沒有。由于只有數組能夠進行快速的隨機訪問,而對鏈表的隨機訪問需要進行鏈表的遍歷。因此,此接口的好處是,可以在利用程序中知道正在處理的 List 對象是不是可以進行快速隨機訪問,從而針對不同的 List 進行不同的操作,以提高程序的性能。

LinkedList 類

LinkedList 實現了 List 接口,允許 Null 元素。另外 LinkedList 提供額外的 Get、Remove、Insert 等方法在 LinkedList 的首部或尾部操作數據。這些操作使得 LinkedList 可被用作堆棧(Stack)、隊列(Queue)或雙向隊列(Deque)。請注意 LinkedList 沒有同步方法,它不是線程同步的,即如果多個線程同時訪問1個 List,則必須自己實現訪問同步。1種解決方法是在創建 List 時構造1個同步的 List,方法如

List list = Collections.synchronizedList(new LinkedList(...));

ArrayList 類

ArrayList 實現了可變大小的數組。它允許所有元素,包括 Null。Size、IsEmpty、Get、Set 等方法的運行時間為常數,但是 Add 方法開消為分攤的常數,添加 N 個元素需要 O(N) 的時間,其他的方法運行時間為線性。
每一個 ArrayList 實例都有1個容量(Capacity),用于存儲元素的數組的大小,這個容量可隨著不斷添加新元素而自動增加。當需要插入大量元素時,在插入前可以調用 ensureCapacity 方法來增加 ArrayList 的容量以提高插入效力。和 LinkedList 1樣,ArrayList 也是線程非同步的(unsynchronized)。

Boolean add(Object o) 將指定元素添加到列表的末尾; Boolean add(int index,Object element) 在列表中指定位置加入指定元素; Boolean addAll(Collection c) 將指定集合添加到列表末尾; Boolean addAll(int index,Collection c) 在列表中指定位置加入指定集合; Boolean clear() 刪除列表中所有元素; Boolean clone() 返回該列表實例的1個拷貝; Boolean contains(Object o) 判斷列表中是不是包括元素; Boolean ensureCapacity(int m) 增加列表的容量,如果必須,該列表能夠容納 m 個元素; Object get(int index) 返回列表中指定位置的元素; int indexOf(Object elem) 在列表中查找指定元素的下標; int size() 返回當前列表的元素個數。

Vector 類

Vector 非常類似于 ArrayList,區分是 Vector 是線程同步的。由 Vector 創建的 Iterator,雖然和 ArrayList 創建的 Iterator 是同1接口,但是,由于 Vector 是同步的,當1個 Iterator 被創建而且正在被使用,另外一個線程改變了 Vector 的狀態(例如,添加或刪除1些元素),這時候調用 Iterator 的方法時將拋出 ConcurrentModificationException,因此必須捕獲該異常。

Stack 類

Stack 繼承自 Vector,實現了1個落后先出的堆棧。Stack 提供 5 個額外的方法使得 Vector 得以被當作堆棧使用。除基本的 Push 和 Pop 方法,還有 Peek 方法得到棧頂的元素,Empty 方法測試堆棧是不是為空,Search 方法檢測1個元素在堆棧中的位置。注意,Stack 剛創建后是空棧。

Set 類

Set 是1種不包括重復的元素的 Collection,即任意的兩個元素 e1 和 e2 都有 e1.equals(e2)=false。Set 最多有1個 null 元素。很明顯,Set 的構造函數有1個束縛條件,傳入的 Collection 參數不能包括重復的元素。請注意,必須謹慎操作可變對象(Mutable Object),如果1個 Set 中的可變元素改變了本身狀態,這可能會致使1些問題。

Hashtable 類

Hashtable 繼承 Map 接口,實現了1個基于 Key-Value 映照的哈希表。任何非空(non-null)的對象都可作為 Key 或 Value。添加數據使用 Put(Key,Value),取出數據使用 Get(Key),這兩個基本操作的時間開消為常數。
Hashtable 通過 Initial Capacity 和 Load Factor 兩個參數調劑性能。通常缺省的 Load Factor 0.75 較好地實現了時間和空間的均衡。增大 Load Factor 可以節省空間但相應的查找時間將增大,會影響像 Get 和 Put 這樣的操作。使用 Hashtable 的簡單示例,將 1、2、3 這3個數字放到 Hashtable 里面,他們的 Key 分別是”one”、”two”、”three”,代碼如清單 2 所示。

Hashtable numbers = new Hashtable(); numbers.put(“one”, new Integer(1)); numbers.put(“two”, new Integer(2)); numbers.put(“three”, new Integer(3)); Integer n = (Integer)numbers.get(“two”); System.out.println(“two =”+ n);

由于作為 Key 的對象將通過計算其散列函數來肯定與之對應的 Value 的位置,因此任何作為 key 的對象都必須實現 HashCode 和 Equals 方法。HashCode 和 Equals 方法繼承自根類 Object,如果你用自定義的類當作 Key 的話,要相當謹慎,依照散列函數的定義,如果兩個對象相同,即 obj1.equals(obj2)=true,則它們的 HashCode 必須相同,但如果兩個對象不同,則它們的 HashCode 不1定不同,如果兩個不同對象的 HashCode 相同,這類現象稱為沖突,沖突會致使操作哈希表的時間開消增大,所以盡可能定義好的 HashCode() 方法,能加快哈希表的操作。
如果相同的對象有不同的 HashCode,對哈希表的操作會出現意想不到的結果(期待的 Get 方法返回 Null),要避免這類問題,最好同時復寫 Equals 方法和 HashCode 方法,而不要只寫其中1個。

HashMap 類

HashMap 和 Hashtable 類似,不同的地方在于 HashMap 是線程非同步的,并且允許 Null,即 Null Value 和 Null Key。但是將 HashMap 視為 Collection 時(values() 方法可返回 Collection),其迭代子操作時間開消和 HashMap 的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將 HashMap 的初始化容量設得太高,或 Load Factor 參數設置太低。

WeakHashMap 類

WeakHashMap 是1種改進的 HashMap,它對 Key 實行“弱援用”,如果1個 Key 不再被外部所援用,那末該 Key 可以被 GC 回收。

實踐

ArrayList、Vector、LinkedList 均來自 AbstractList 的實現,而 AbstractList 直接實現了 List 接口,并擴大自 AbstarctCollection。ArrayList 和 Vector 使用了數組實現,ArrayList 沒有對任何1個方法提供線程同步,因此不是線程安全的,Vector 中絕大部份方法都做了線程同步,是1種線程安全的實現。LinkedList 使用了循環雙向鏈表數據結構,由1系列表項連接而成,1個表項總是包括 3 個部份,元素內容、先驅表項和后驅表項。
當 ArrayList 對容量的需求超過當前數組的大小時,需要進行擴容。擴容進程中,會進行大量的數組復制操作,而數組復制時,終究將調用 System.arraycopy() 方法。LinkedList 由于使用了鏈表的結構,因此不需要保護容量的大小,但是每次的元素增加都需要新建1個 Entry 對象,并進行更多的賦值操作,在頻繁的系統調用下,對性能會產生1定的影響,在不中斷地生成新的對象還是占用了1定的資源。而由于數組的連續性,因此總是在尾端增加元素時,只有在空間不足時才產生數組擴容和數組復制。
ArrayList 是基于數組實現的,而數組是1塊連續的內存空間,如果在數組的任意位置插入元素,必定致使在該位置后的所有元素需要重新排列,因此其效力較差,盡量將數據插入到尾部。LinkedList 不會由于插入數據致使性能降落。
ArrayList 的每次有效的元素刪除操作后都要進行數組的重組,并且刪除的元素位置越靠前,數組重組時的開消越大,要刪除的元素位置越靠后,開消越小。LinkedList 要移除中間的數據需要便利完半個 List。

import java.util.ArrayList; import java.util.LinkedList; public class ArrayListandLinkedList { public static void main(String[] args){ long start = System.currentTimeMillis(); ArrayList list = new ArrayList(); Object obj = new Object(); for(int i=0;i<5000000;i++){ list.add(obj); } long end = System.currentTimeMillis(); System.out.println(end-start); start = System.currentTimeMillis(); LinkedList list1 = new LinkedList(); Object obj1 = new Object(); for(int i=0;i<5000000;i++){ list1.add(obj1); } end = System.currentTimeMillis(); System.out.println(end-start); start = System.currentTimeMillis(); Object obj2 = new Object(); for(int i=0;i<1000;i++){ list.add(0,obj2); } end = System.currentTimeMillis(); System.out.println(end-start); start = System.currentTimeMillis(); Object obj3 = new Object(); for(int i=0;i<1000;i++){ list1.add(obj1); } end = System.currentTimeMillis(); System.out.println(end-start); start = System.currentTimeMillis(); list.remove(0); end = System.currentTimeMillis(); System.out.println(end-start); start = System.currentTimeMillis(); list1.remove(250000); end = System.currentTimeMillis(); System.out.println(end-start); } }

HashMap 是將 Key 做 Hash 算法,然后將 Hash 值映照到內存地址,直接獲得 Key 所對應的數據。在 HashMap 中,底層數據結構使用的是數組,所謂的內存地址即數組的下標索引。HashMap 的高性能需要保證以下幾點:
Hash 算法必須是高效的;
Hash 值到內存地址 (數組索引) 的算法是快速的;
根據內存地址 (數組索引) 可以直接獲得對應的值。
HashMap 實際上是1個鏈表的數組。前面已介紹過,基于 HashMap 的鏈表方式實現機制,只要 HashCode() 和 Hash() 方法實現得足夠好,能夠盡量地減少沖突的產生,那末對 HashMap 的操作幾近等價于對數組的隨機訪問操作,具有很好的性能。但是,如果 HashCode() 或 Hash() 方法實現較差,在大量沖突產生的情況下,HashMap 事實上就退化為幾個鏈表,對 HashMap 的操作等價于遍歷鏈表,此時性能很差。
HashMap 的1個功能缺點是它的無序性,被存入到 HashMap 中的元素,在遍歷 HashMap 時,其輸出是無序的。如果希望元素保持輸入的順序,可使用 LinkedHashMap 替換。
LinkedHashMap 繼承自 HashMap,具有高效性,同時在 HashMap 的基礎上,又在內部增加了1個鏈表,用以寄存元素的順序。
HashMap 通過 hash 算法可以最快速地進行 Put() 和 Get() 操作。TreeMap 則提供了1種完全不同的 Map 實現。從功能上講,TreeMap 有著比 HashMap 更加強大的功能,它實現了 SortedMap 接口,這意味著它可以對元素進行排序。TreeMap 的性能稍微低于 HashMap。如果在開發中需要對元素進行排序,那末使用 HashMap 便沒法實現這類功能,使用 TreeMap 的迭代輸出將會以元素順序進行。LinkedHashMap 是基于元素進入集合的順序或被訪問的前后順序排序,TreeMap 則是基于元素的固有順序 (由 Comparator 或 Comparable 肯定)。
LinkedHashMap 是根據元素增加或訪問的前后順序進行排序,而 TreeMap 則根據元素的 Key 進行排序。

import java.util.Iterator; import java.util.Map; import java.util.TreeMap; public class Student implements Comparable<Student>{ public String name; public int score; public Student(String name,int score){ this.name = name; this.score = score; } @Override //告知 TreeMap 如何排序 public int compareTo(Student o) { // TODO Auto-generated method stub if(o.score<this.score){ return 1; }else if(o.score>this.score){ return -1; } return 0; } @Override public String toString(){ StringBuffer sb = new StringBuffer(); sb.append("name:"); sb.append(name); sb.append(" "); sb.append("score:"); sb.append(score); return sb.toString(); } public static void main(String[] args){ TreeMap map = new TreeMap(); Student s1 = new Student("1",100); Student s2 = new Student("2",99); Student s3 = new Student("3",97); Student s4 = new Student("4",91); map.put(s1, new StudentDetailInfo(s1)); map.put(s2, new StudentDetailInfo(s2)); map.put(s3, new StudentDetailInfo(s3)); map.put(s4, new StudentDetailInfo(s4)); //打印分數位于 S4 和 S2 之間的人 Map map1=((TreeMap)map).subMap(s4, s2); for(Iterator iterator=map1.keySet().iterator();iterator.hasNext();){ Student key = (Student)iterator.next(); System.out.println(key+"->"+map.get(key)); } System.out.println("subMap end"); //打印分數比 s1 低的人 map1=((TreeMap)map).headMap(s1); for(Iterator iterator=map1.keySet().iterator();iterator.hasNext();){ Student key = (Student)iterator.next(); System.out.println(key+"->"+map.get(key)); } System.out.println("subMap end"); //打印分數比 s1 高的人 map1=((TreeMap)map).tailMap(s1); for(Iterator iterator=map1.keySet().iterator();iterator.hasNext();){ Student key = (Student)iterator.next(); System.out.println(key+"->"+map.get(key)); } System.out.println("subMap end"); } } class StudentDetailInfo{ Student s; public StudentDetailInfo(Student s){ this.s = s; } @Override public String toString(){ return s.name + "'s detail information"; } }

WeakHashMap 特點是當除本身有對 Key 的援用外,如果此 Key 沒有其他援用,那末此 Map 會自動拋棄該值。如清單 8 所示代碼聲明了兩個 Map 對象,1個是 HashMap,1個是 WeakHashMap,同時向兩個 map 中放入 A、B 兩個對象,當 HashMap 刪除 A,并且 A、B 都指向 Null 時,WeakHashMap 中的 A 將自動被回收掉。出現這個狀態的緣由是,對 A 對象而言,當 HashMap 刪除并且將 A 指向 Null 后,除 WeakHashMap 中還保存 A 外已沒有指向 A 的指針了,所以 WeakHashMap 會自動舍棄掉 a,而對 B 對象雖然指向了 null,但 HashMap 中還有指向 B 的指針,所以 WeakHashMap 將會保存 B 對象。

import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; public class WeakHashMapTest { public static void main(String[] args) throws Exception { String a = new String("a"); String b = new String("b"); Map weakmap = new WeakHashMap(); Map map = new HashMap(); map.put(a, "aaa"); map.put(b, "bbb"); weakmap.put(a, "aaa"); weakmap.put(b, "bbb"); map.remove(a); a=null; b=null; System.gc(); Iterator i = map.entrySet().iterator(); while (i.hasNext()) { Map.Entry en = (Map.Entry)i.next(); System.out.println("map:"+en.getKey()+":"+en.getValue()); } Iterator j = weakmap.entrySet().iterator(); while (j.hasNext()) { Map.Entry en = (Map.Entry)j.next(); System.out.println("weakmap:"+en.getKey()+":"+en.getValue()); } } }

WeakHashMap 主要通過 expungeStaleEntries 這個函數來實現移除其內部不用的條目,從而到達自動釋放內存的目的。基本上只要對 WeakHashMap 的內容進行訪問就會調用這個函數,從而到達清除其內部不再為外部援用的條目。但是如果預先生成了 WeakHashMap,而在 GC 之前又不曾訪問該 WeakHashMap, 那不是就不能釋放內存了嗎?

import java.util.ArrayList; import java.util.List; import java.util.WeakHashMap; public class WeakHashMapTest1 { public static void main(String[] args) throws Exception { List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>(); for (int i = 0; i < 1000; i++) { WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>(); d.put(new byte[1000][1000], new byte[1000][1000]); maps.add(d); System.gc(); System.err.println(i); } } }
241 242 243 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at WeakHashMapTest1.main(WeakHashMapTest1.java:10)

出現內存溢出問題,WeakHashMap 這個時候并沒有自動幫我們釋放不用的內存。

import java.util.ArrayList; import java.util.List; import java.util.WeakHashMap; public class WeakHashMapTest2 { public static void main(String[] args) throws Exception { List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>(); for (int i = 0; i < 1000; i++) { WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>(); d.put(new byte[1000][1000], new byte[1000][1000]); maps.add(d); System.gc(); System.err.println(i); for (int j = 0; j < i; j++) { System.err.println(j + " size" + maps.get(j).size()); } } } }

運行結果發現這次測試輸出正常, 不再出現內存溢出問題。
總的來講,WeakHashMap 其實不是你甚么也干它就可以自動釋放內部不用的對象的,而是在你訪問它的內容的時候釋放內部不用的對象。
WeakHashMap 實現弱援用,是由于它的 Entry

WeakHashMap private static class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V> Entry(K key, V value, ReferenceQueue<K> queue,int hash, Entry<K,V> next) { super(key, queue); this.value = value; this.hash = hash; this.next = next; }

請注意它構造父類的語句:“super(key, queue);”,傳入的是 Key,因此 Key 才是進行弱援用的,Value 是直接強援用關聯在 this.value 當中。在 System.gc() 時,Key 中的 Byte 數組進行了回收,而 Value 仍然保持 (Value 被強關聯到 Entry 上,Entry 又關聯在 Map 中,Map 關聯在 ArrayList 中)。
For 循環中每次都 New 1個新的 WeakHashMap,在 Put 操作后,雖然 GC 將 WeakReference 的 Key 中的 Byte 數組回收了,并將事件通知到了 ReferenceQueue,但后續卻沒有相應的動作去觸發 WeakHashMap 去處理 ReferenceQueue,所以 WeakReference 包裝 Key 仍然存在于 WeakHashMap 中,其對應的 value 也固然存在。
那 value 是什么時候被清除的呢? 對清單 10 和清單 11 兩個示例程序進行分析可知,清單 11 的 maps.get(j).size() 觸發了 Value 的回收,那又如何觸發的呢?查看 WeakHashMap 源碼可知,Size 方法調用了 expungeStaleEntries 方法,該方法對 JVM 要回收的的 Entry(Quene 中) 進行遍歷,并將 Entry 的 Value 置空,回收了內存。所以效果是 Key 在 GC 的時候被清除,Value 在 Key 清除后訪問 WeakHashMap 被清除。
WeakHashMap 類是線程不同步的,可使用 Collections.synchronizedMap 方法來構造同步的 WeakHashMap, 每一個鍵對象間接地存儲為1個弱援用的唆使對象。因此,不論是在映照內還是在映照以外,只有在垃圾回收器清除某個鍵的弱援用以后,該鍵才會自動移除。需要注意的是,WeakHashMap 中的值對象由普通的強援用保持。因此應當謹慎謹慎,確保值對象不會直接或間接地強援用其本身的鍵,由于這會禁止鍵的拋棄。注意,值對象可以通過 WeakHashMap 本身間接援用其對應的鍵,這就是說,某個值對象可能強援用某個其他的鍵對象,而與該鍵對象相干聯的值對象轉而強援用第1個值對象的鍵。
處理此問題的1種方法是,在插入前將值本身包裝在 WeakReferences 中,如:m.put(key, new WeakReference(value)),然后,分別用 get 進行解包,該類所有“collection 視圖方法”返回的迭代器均是快速失敗的,在迭代器創建以后,如果從結構上對映照進行修改,除非通過迭代器本身的 Remove 或 Add 方法,其他任什么時候間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。因此,面對并發的修改,迭代器很快就完全失敗,而不是冒著在將來不肯定的時間任意產生不肯定行動的風險。
注意,我們不能確保迭代器不失敗,1般來講,存在不同步的并發修改時,不可能做出任何完全肯定的保證。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 天天操天天射天天爽 | 成人动漫一区二区三区 | 欧美成人在线免费 | 久久中文字幕一区二区 | 一级肉体全黄裸片 | 欧美日韩一区二区在线观看 | 欧美日本国产在线 | 成年人免费在线观看 | 亚洲色图28p | 女人夜夜春 | 亚洲网站在线播放 | 美女视频国产 | 欧美成人在线免费视频 | 91精品国产91久久久久久吃药 | 国产一区二区成人在线 | av麻豆| 久久久久成人精品 | 一级片自拍 | 国产高清一区二区 | 久久99精品久久久久久久青青日本 | 最近最好最新2019中文字幕免费 | 成人精品一区二区户外勾搭野战 | 免费高清日本 | 伊人91在线 | 精品一级| 国产激情综合五月久久 | 欧美福利一区二区三区 | 国产伦精品一区二区三区高清版 | 最新日韩精品 | 国产一区二区三区片 | 成人免费观看视频大全 | 久久九九国产 | 日本视频不卡 | 最近中文字幕免费视频 | 激情免费视频 | 久久久午夜视频 | 啪啪av大全导航福利综合导航 | 精品国产鲁一鲁一区二区张丽 | 99国产精品视频免费观看一公开 | 国产精品不卡在线 | 国产第一精品 |