日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA集合和guava集合使用和原理解析

發布時間:2023/12/9 编程问答 74 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA集合和guava集合使用和原理解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

一:總體介紹:

Java集合框架介紹

?集合可以看作是一種容器,用來存儲對象信息。所有集合類都位于java.util包下,但支持多線程的集合類位于java.util.concurrent包下。

Java集合類主要由兩個根接口Collection和Map派生出來的,Collection派生出了三個子接口:List、Set、Queue(Java5新增的隊列),因此Java集合大致也可分成List、Set、Queue、Map四種接口體系,(注意:Map不是Collection的子接口)。

其中List代表了有序可重復集合,可直接根據元素的索引來訪問;Set代表無序不可重復集合,只能根據元素本身來訪問;Queue是隊列集合;Map代表的是存儲key-value對的集合,可根據元素的key來訪問value。

?Java集合和數組的區別:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

  • 已定義集合的大小可變,而已定義的數組大小不可變(注意:集合內部實現機制也用到了對象數組,只是通過數組的復制或鏈式存儲的方式使其從外部看起來是可變的,而其本身并未顛覆數組大小不可變這一觀點)
  • 數組可以存儲基本數據類型和引用類型,而集合只能存儲引用類型,例如傳入add方法中的int會被自動封裝成Integer類型
  • 數組只能存儲相同類型的數據,而集合如未確定泛型的具體類型,則可存儲任意引用類型數據
  • Guava集合框架介紹

    ?

    Guava 是一款 Google 開源工具類,包含許多 Google 內部?Java?項目依賴的核心類。Guava 擴展 Java 基礎類工程,比如集合,并發等,也增加一些其他強大功能,比如緩存,限流等功能。另外 Guava 推出一些類,如?Optional,甚至被 Java 開發者學習,后續增加到 JDK 中。Guava 創造很多 JDK 沒有,但是我們日常卻明顯有用的新集合類型。這些新類型使用 JDK 集合接口規范,所以使用方法與 JDK 集合框架差不多,并沒有增加很多使用難度。

    ?

    集合接口屬于JDK還是Guava對應的Guava工具類
    CollectionJDKCollections2:不要和java.util.Collections混淆
    ListJDKLists
    SetJDKSets
    SortedSetJDKSets
    MapJDKMaps
    SortedMapJDKMaps
    QueueJDKQueues
    MultisetGuavaMultisets
    MultimapGuavaMultimaps
    BiMapGuavaMaps
    TableGuavaTables


    二:接口及類詳解【JAVA】

    Iterable<T> 接口

    常用方法:

    方法名或屬性名稱描述注意事項備注
    Iterator<T> iterator(); 返回每個元素的迭代器 ??
    default void forEach(Consumer<? super T> action)

    循環操作每個元素

    ?
    default Spliterator<T> spliterator()

    創建一個spliterator

    ??

    重點方法介紹及代碼示例

    /*** iteable測試類*/ public class TestItearble {// 返回迭代器,hasNext方法判斷是否有下一個元素 next方法取下一個元素public static void testIterator(List<Integer> list) {Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}// foreach 內部用的還是iteratorpublic static void testForeach(Set<String> set) {set.forEach(System.out::println);}public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(1);list.add(3);list.add(4);testIterator(list);Set<String> set = new HashSet<>();set.add("one");set.add("three");set.add("four");set.add("one");testForeach(set);}

    spliterator是java1.8新提出的能夠進行并行遍歷的迭代器.首先, iterator是專門用于迭代集合元素的方法,在List類中就有iterator()方法.集合通過調用Iterator方法,可以對該集合進行循環,效果就相當于是使用了for循環,但是iterator的好處就是不論是List,還是Map,都可以通過iterator進行遍歷.但是,通過iterator和for循環一樣,都是單線程的操作,Spliterator也用于遍歷數據源中的元素,但它是為了并行執行而設計的。Java 8已經為集合框架中包含的所有數據結構提供了一個默認的Spliterator實現。集合實現了Spliterator接口,接口提供了一個spliterator方法。詳解可見:https://blog.csdn.net/sl1992/article/details/100149187?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param

    public class TestSplitror {private static class Thread<T> extends java.lang.Thread {private final Spliterator<T> list;private Thread(Spliterator<T> list) {this.list = list;}@Overridepublic void run() {list.forEachRemaining(System.out::println);}}public static void main(String[] args) {List<String> list = new ArrayList<>();for (int i = 0; i < 2000; i++) {list.add("split" + i);}// 拆分迭代器Spliterator<String> spliterator = list.spliterator();Spliterator<String> stringSpliterator = spliterator.trySplit();Thread<String> stringthread = new Thread<>(spliterator);Thread<String> stringthread1 = new Thread<>(stringSpliterator);stringthread.start();stringthread1.start();while (true) {if (stringthread.isAlive() || stringthread1.isAlive()) {try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}} else {break;}}System.out.println("main end");}}

    Collection<E> 接口

    常用方法

    方法名或屬性名稱描述注意事項備注
    int size(); 返回集合的元素數量 如果元素數量超過Integer.MAX_VALUE返回Integer.MAX_VALUE. ?
    boolean isEmpty(); 返回集合是否沒有元素 ??
    boolean contains(Object o); 如果集合有該元素返回true ClassCastException 元素類型不相容 ?
    Object[] toArray(); 返回一個裝有改集合元素的數組 排序 <T> T[] toArray(T[] a)該方法可以對返回的數組類型進行精確控制。而非像toArray方法一樣返回Object[]。
    boolean add(E e); 添加一個元素,添加成功返回true ?
    boolean remove(Object o); 移除一個元素,移除成功返回true ?
    boolean containsAll(Collection<?> c); 是否存在當前集合中的所有元素 ?
    boolean addAll(Collection<? extends E> c); 添加當前集合中的所有元素 ?
    boolean removeAll(Collection<?> c); 移除當前集合中的所有元素 ?
    default boolean removeIf(Predicate<? super E> filter) 根據給定的公式移除元素 ?
    default Stream<E> stream() 返回streeam流 ??
    default Stream<E> parallelStream() 返回并行stream流 ??


    重點方法介紹及代碼示例

    add() 向集合中添加一個元素。集合更改則添加成功返回true,如果該集合不允許重復并且已經包含指定的元素。返回false。部分子類的add方法可能會限制添加到集合中的元素類型,或者不會將NULL添加到集合中。
    public class TestCollectionApi {public static void main(String[] args) {Collection set = new HashSet<>();boolean one = set.add("one");boolean one1 = set.add("one");System.out.println("set第一次添加add" + one);System.out.println("set第二次添加add" + one1);Collection list = new ArrayList<>();boolean one2 = list.add("list");boolean one3 = list.add("list");System.out.println("list第一次添加add" + one2);System.out.println("list第二次添加add" + one3);}} 返回結果為:true false true true

    List<E>接口

    一個排序的集合(也被稱作序列),接口使用者可以精確控制每個元素在集合中的插入位置,用戶可以根據integer類型的索引訪問和搜索集合中的元素。不像set,集合通常允許重復的元素,如果他們允許null元素存在的話,也可以存在重復的null。

    ?

    方法名或屬性名稱描述注意事項備注
    default void replaceAll(UnaryOperator<E> operator) 將此列表中的每個元素替換為對該元素應用運算符的結果。??
    default void sort(Comparator<? super E> c) 根據明確的比較器進行排序??
    E get(int index); 返回該位置的元素??
    E set(int index, E element); 用明確的元素替換明確位置的元素。??
    void add(int index, E element); 插入元素到固定的位置,原該位置元素及后面的元素索引加一。??
    E remove(int index); 移除具體位置的元素,后面的元素索引減一??
    int indexOf(Object o); 返回該元素的索引位置或者返回-1(如果不存在)??
    ListIterator<E> listIterator(); 返回一個list迭代器 int lastIndexOf(Object o);返回最后一個該元素的索引位置或者-1(不存在)
    List<E> subList(int fromIndex, int toIndex); 返回一個前閉后開的視圖。??

    重點方法介紹及代碼示例

    public class TestListApi {public static void main(String[] args) {List<String> list = new LinkedList<>();list.add("a");list.add("b");list.add("c");list.set(1, "d");System.out.println(list);list.add(1, "k");System.out.println(list);list.replaceAll(x -> {if (x.equals("a")) {return "tt";}return x;});System.out.println(list);list.sort(String::compareTo);System.out.println(list);List<String> list1 = list.subList(0, 2);list1.set(0, "kkkk");System.out.println(list);} } 返回結果為: [a, d, c] [a, k, d, c] [tt, k, d, c] [c, d, k, tt] [kkkk, d, k, tt]

    Set<E>接口

    ?

    元素無放入順序,元素不可重復(注意:元素雖然無放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實是固定的) Set接口有兩個實現類:HashSet(底層由HashMap實現),LinkedHashSet? SortedSet接口有一個實現類:TreeSet(底層由平衡二叉樹實現) Set : 存入Set的每個元素都必須是唯一的,因為Set不保存重復元素。加入Set的元素必須定義equals()方法以確保對象的唯一性。Set與Collection有完全一樣的接口。Set接口不保證維護元素的次序。 HashSet : 為快速查找設計的Set。存入HashSet的對象必須定義hashCode()。 TreeSet : 保存次序的Set, 底層為樹結構。使用它可以從Set中提取有序的序列。 LinkedHashSet : 具有HashSet的查詢速度,且內部使用鏈表維護元素的順序(插入的次序)。于是在使用迭代器遍歷Set時,結果會按元素插入的次序顯示。 方法名或屬性名稱描述注意事項備注
    boolean contains(Object o); 如果集合有該元素返回true ClassCastException 元素類型不相容 ?
    Object[] toArray(); 返回一個裝有改集合元素的數組 排序 <T> T[] toArray(T[] a)該方法可以對返回的數組類型進行精確控制。而非像toArray方法一樣返回Object[]。
    boolean add(E e); 添加一個元素,添加成功返回true ?
    boolean remove(Object o); 移除一個元素,移除成功返回true ?
    boolean containsAll(Collection<?> c); 是否存在當前集合中的所有元素 ?
    boolean retainAll(Collection<?> c); 取交集 ??
    boolean addAll(Collection<? extends E> c); 添加當前集合中的所有元素 ?
    boolean removeAll(Collection<?> c); 移除當前集合中的所有元素 ?
    default boolean removeIf(Predicate<? super E> filter) 根據給定的公式移除元素 ?

    TreeSet

    TreeSet實現了SortedSet接口,它是一個有序的集合類,TreeSet的底層是通過TreeMap實現的。TreeSet并不是根據插入的順序來排序,而是根據實際的值的大小來排序。TreeSet也支持兩種排序方式:

    1:自然排序。2:自定義排序

    如何保證排序和唯一性?

    public V put(K key, V value) { // 先以 t 保存鏈表的 root 節點Entry<K,V> t = root; // 如果 t==null,表明是一個空鏈表,即該 TreeMap 里沒有任何 Entry if (t == null) { // 將新的 key-value 創建一個 Entry,并將該 Entry 作為 root root = new Entry<K,V>(key, value, null); // 設置該 Map 集合的 size 為 1,代表包含一個 Entry size = 1; // 記錄修改次數為 1 modCount++; return null; } int cmp; Entry<K,V> parent; Comparator<? super K> cpr = comparator; // 如果比較器 cpr 不為 null,即表明采用定制排序if (cpr != null) { do { // 使用 parent 上次循環后的 t 所引用的 Entry parent = t; // 拿新插入 key 和 t 的 key 進行比較cmp = cpr.compare(key, t.key); // 如果新插入的 key 小于 t 的 key,t 等于 t 的左邊節點if (cmp < 0) t = t.left; // 如果新插入的 key 大于 t 的 key,t 等于 t 的右邊節點else if (cmp > 0) t = t.right; // 如果兩個 key 相等,新的 value 覆蓋原有的 value,// 并返回原有的 value else return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); Comparable<? super K> k = (Comparable<? super K>) key; do { // 使用 parent 上次循環后的 t 所引用的 Entry parent = t; // 拿新插入 key 和 t 的 key 進行比較cmp = k.compareTo(t.key); // 如果新插入的 key 小于 t 的 key,t 等于 t 的左邊節點if (cmp < 0) t = t.left; // 如果新插入的 key 大于 t 的 key,t 等于 t 的右邊節點else if (cmp > 0) t = t.right; // 如果兩個 key 相等,新的 value 覆蓋原有的 value,// 并返回原有的 value else return t.setValue(value); } while (t != null); } // 將新插入的節點作為 parent 節點的子節點Entry<K,V> e = new Entry<K,V>(key, value, parent); // 如果新插入 key 小于 parent 的 key,則 e 作為 parent 的左子節點if (cmp < 0) parent.left = e; // 如果新插入 key 小于 parent 的 key,則 e 作為 parent 的右子節點else parent.right = e; // 修復紅黑樹fixAfterInsertion(e); // ①size++; modCount++; return null; } // 每當程序希望添加新節點時:系統總是從樹的根節點開始比較 —— 即將根節點當成當前節點,如果新增節點大于當前節點、并且當前節點的右子節點存在,則以右子節點作為當前節點;如果新增節點小于當前節點、并且當前節點的左子節點存在,則以左子節點作為當前節點;如果新增節點等于當前節點,則用新增節點覆蓋當前節點,并結束循環 —— 直到找到某個節點的左、右子節點不存在,將新節點添加該節點的子節點 —— 如果新節點比該節點大,則添加為右子節點;如果新節點比該節點小,則添加為左子節點。

    TreeSet的底層實現

    簡單來說 treeset就是沒有重復元素的treemap

    public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable { // 使用 NavigableMap 的 key 來保存 Set 集合的元素private transient NavigableMap<E,Object> m; // 使用一個 PRESENT 作為 Map 集合的所有 value。private static final Object PRESENT = new Object(); // 包訪問權限的構造器,以指定的 NavigableMap 對象創建 Set 集合TreeSet(NavigableMap<E,Object> m) { this.m = m; } public TreeSet() // ①{ // 以自然排序方式創建一個新的 TreeMap,// 根據該 TreeSet 創建一個 TreeSet,// 使用該 TreeMap 的 key 來保存 Set 集合的元素this(new TreeMap<E,Object>()); } public TreeSet(Comparator<? super E> comparator) // ②{ // 以定制排序方式創建一個新的 TreeMap,// 根據該 TreeSet 創建一個 TreeSet,// 使用該 TreeMap 的 key 來保存 Set 集合的元素this(new TreeMap<E,Object>(comparator)); } public TreeSet(Collection<? extends E> c) { // 調用①號構造器創建一個 TreeSet,底層以 TreeMap 保存集合元素this(); // 向 TreeSet 中添加 Collection 集合 c 里的所有元素addAll(c); } public TreeSet(SortedSet<E> s) { // 調用②號構造器創建一個 TreeSet,底層以 TreeMap 保存集合元素this(s.comparator()); // 向 TreeSet 中添加 SortedSet 集合 s 里的所有元素addAll(s); } } //從上面代碼可以看出,TreeSet 的 ① 號、② 號構造器的都是新建一個 TreeMap 作為實際存儲 Set 元素的容器,而另外 2 個構造器則分別依賴于 ① 號和 ② 號構造器,由此可見,TreeSet 底層實際使用的存儲容器就是 TreeMap。


    注意:如果想實現自然排序,那么需保證排序的類實現了comparable接口,否則會拋出java.lang.ClassCastException

    ArrayList

    官方解釋:List接口的動態數組實現,允許所有類型,包括null,除了實現List接口之外,此類提供方法來操作內部用于存儲列表。這個類大致相當于Vector,但它不是同步的。

    ArrayList初始化

    ?

    public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {private static final long serialVersionUID = 8683452581122892189L;/*** 默認的容量*/private static final int DEFAULT_CAPACITY = 10;/*** 空數組,當調用無參數構造函數的時候默認給個空數組*/private static final Object[] EMPTY_ELEMENTDATA = {};/*** * 空數組,當調用無參數構造函數的時候默認給個空數組,我們將其與空的元素數據區分開來,以了解添加第一個元素時要膨脹多少。*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** 存儲ArrayList中元素的數組容器,ArrayList的容量就是數組的長度,任何一個空的數組都會被拓展到DEFAULT_CAPACITY個容量,當第一個元素添加時。*/transient Object[] elementData; // non-private to simplify nested class access/*** 包含的元素的數量*/private int size;/*** 構造方法傳入默認的capacity 設置默認數組大小*/public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}/*** 無參數構造方法默認為空數組*/public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;} // get方法 public E get(int index) {rangeCheck(index);return elementData(index); } E elementData(int index) {return (E) elementData[index]; }}

    ArrayList動態擴容

    public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {/*** 添加一個元素到列表的尾部*/ public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true; }private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity); } private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity; } /*** 增加容量確保他可以保存minCapacity的元素*/ private void grow(int minCapacity) {// 首先容量翻1.5倍int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);// 翻倍之后還不滿足,容量賦值為所需最小容量if (newCapacity - minCapacity < 0)newCapacity = minCapacity;// 最大值為Integer.MAX_VALUEif (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// 將原來數組的值copy新數組中去, ArrayList的引用指向新數組elementData = Arrays.copyOf(elementData, newCapacity); }private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE : MAX_ARRAY_SIZE; }/*** 移除制定位置的元素,返回值為被移除的元素*/ public E remove(int index) {rangeCheck(index);modCount++;E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)// 移除元素右邊的元素左移System.arraycopy(elementData, index+1, elementData, index,numMoved);// 最后一位置空elementData[--size] = null; // clear to let GC do its work ???return oldValue; } }

    Array.copyOf與System.ArrayCopyOf

    ?

    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {@SuppressWarnings("unchecked")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; }

    由此可見Array.copyOf與System.ArrayCopyOf均為淺拷貝。

    HashMap

    ?

    HashMap?是一個關聯數組、哈希表,它是線程不安全的,允許key為null,value為null。遍歷時無序。其底層數據結構是數組稱之為哈希桶,每個桶里面放的是鏈表,鏈表中的每個節點,就是哈希表中的每個元素。
    在JDK8中,當鏈表長度達到8,會轉化成紅黑樹,以提升它的查詢、插入效率.

    ?

    因其底層哈希桶的數據結構是數組,所以也會涉及到擴容的問題。

    當HashMap的容量達到threshold域值時,就會觸發擴容。擴容前后,哈希桶的長度一定會是2的次方。這樣在根據key的hash值尋找對應的哈希桶時,可以用位運算替代取余操作,更加高效。而key的hash值,并不僅僅只是key對象的hashCode()方法的返回值,還會經過擾動函數的擾動,以使hash值更加均衡。

    但就算原本的hashCode()取得很好,每個key的hashCode()不同,但是由于HashMap的哈希桶的長度遠比hash取值范圍小,默認是16,所以當對hash值以桶的長度取余,以找到存放該key的桶的下標時,由于取余是通過與操作完成的,會忽略hash值的高位。因此只有hashCode()的低位參加運算,發生不同的hash值,但是得到的index相同的情況的幾率會大大增加,這種情況稱之為hash碰撞。?即,碰撞率會增大。擾動函數就是為了解決hash碰撞的。它會綜合hash值高位和低位的特征,并存放在低位,因此在與運算時,相當于高低位一起參與了運算,以減少hash碰撞的概率。(在JDK8之前,擾動函數會擾動四次,JDK8簡化了這個操作)

    ?

    擴容操作時,會new一個新的Node數組作為哈希桶,然后將原哈希表中的所有數據(Node節點)移動到新的哈希桶中,相當于對原哈希表中所有的數據重新做了一個put操作。所以性能消耗很大,可想而知,在哈希表的容量越大時,性能消耗越明顯。

    ?

    數據域

    /*** 默認初始容量16*/ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16/*** 最大容量必須小于 1 << 3*/ static final int MAXIMUM_CAPACITY = 1 << 30;/*** load factor */ static final float DEFAULT_LOAD_FACTOR = 0.75f;/*** 當add一個元素到某個位桶,其鏈表長度達到8時將鏈表轉換為紅黑樹*/ static final int TREEIFY_THRESHOLD = 8;/****/ static final int UNTREEIFY_THRESHOLD = 6; /*** 存儲元素的數組*/ transient Node<K,V>[] table;/*** */ transient Set<Map.Entry<K,V>> entrySet;/*** 包含的鍵值對的個數*/ transient int size;/*** 結構性修改的次數,fast—fail機制*/ transient int modCount; /*** */ int threshold;/*** The load factor for the hash table.*/ final float loadFactor;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;}public final K getKey() { return key; }public final V getValue() { return value; }public final String toString() { return key + "=" + value; }//每一個節點的hash值,是將key的hashCode 和 value的hashCode 亦或得到的。public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}//設置新的value 同時返回舊valuepublic 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;}}

    構造函數

    public HashMap() {//默認構造函數,賦值加載因子為默認的0.75fthis.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted}public HashMap(int initialCapacity) {//指定初始化容量的構造函數this(initialCapacity, DEFAULT_LOAD_FACTOR);}//同時指定初始化容量 以及 加載因子, 用的很少,一般不會修改loadFactorpublic HashMap(int initialCapacity, float loadFactor) {//邊界處理if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " +initialCapacity);//初始容量最大不能超過2的30次方if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;//加載因子不能為負數if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " +loadFactor);this.loadFactor = loadFactor;//設置閾值為 》=初始化容量的 2的n次方的值this.threshold = tableSizeFor(initialCapacity);}//新建一個哈希表,同時將另一個map m 里的所有元素加入表中public HashMap(Map<? extends K, ? extends V> m) {this.loadFactor = DEFAULT_LOAD_FACTOR;putMapEntries(m, false);}//根據期望容量cap,返回2的n次方形式的 哈希桶的實際容量 length。 返回值一般會>=cap static final int tableSizeFor(int cap) {//經過下面的 或 和位移 運算, n最終各位都是1。int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;//判斷n是否越界,返回 2的n次方作為 table(哈希桶)的閾值return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}

    擴容機制

    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) {//tab存放 當前的哈希桶, p用作臨時鏈表節點 Node<K,V>[] tab; Node<K,V> p; int n, i;//如果當前哈希表是空的,代表是初始化if ((tab = table) == null || (n = tab.length) == 0)//那么直接去擴容哈希表,并且將擴容后的哈希桶長度賦值給nn = (tab = resize()).length;//如果當前index的節點是空的,表示沒有發生哈希碰撞。 直接構建一個新節點Node,掛載在index處即可。// index 是利用 哈希值 & 哈希桶的長度-1,替代模運算if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {//否則 發生了哈希沖突。//eNode<K,V> e; K k;//如果哈希值相等,key也相等,則是覆蓋value操作if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;//將當前節點引用賦值給eelse 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);//如果追加節點后,鏈表數量》=8,則轉化為紅黑樹if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}//如果找到了要覆蓋的節點if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}//如果e不是null,說明有需要覆蓋的節點,if (e != null) { // existing mapping for key//則覆蓋節點值,并返回原oldValueV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;//這是一個空實現的函數,用作LinkedHashMap重寫使用。afterNodeAccess(e);return oldValue;}}//如果執行到了這里,說明插入了一個新的節點,所以會修改modCount,以及返回null。//修改modCount++modCount;//更新size,并判斷是否需要擴容。if (++size > threshold)resize();//這是一個空實現的函數,用作LinkedHashMap重寫使用。afterNodeInsertion(evict);return null;}final Node<K,V>[] resize() {//oldTab 為當前表的哈希桶Node<K,V>[] oldTab = table;//當前哈希桶的容量 lengthint oldCap = (oldTab == null) ? 0 : oldTab.length;//當前的閾值int oldThr = threshold;//初始化新的容量和閾值為0int newCap, newThr = 0;//如果當前容量大于0if (oldCap > 0) {//如果當前容量已經到達上限if (oldCap >= MAXIMUM_CAPACITY) {//則設置閾值是2的31次方-1threshold = Integer.MAX_VALUE;//同時返回當前的哈希桶,不再擴容return oldTab;}//否則新的容量為舊的容量的兩倍。 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)//如果舊的容量大于等于默認初始容量16//那么新的閾值也等于舊的閾值的兩倍newThr = oldThr << 1; // double threshold}//如果當前表是空的,但是有閾值。代表是初始化時指定了容量、閾值的情況else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;//那么新表的容量就等于舊的閾值else {}//如果當前表是空的,而且也沒有閾值。代表是初始化時沒有任何容量/閾值參數的情況 newCap = DEFAULT_INITIAL_CAPACITY;//此時新表的容量為默認的容量 16newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);//新的閾值為默認容量16 * 默認加載因子0.75f = 12}if (newThr == 0) {//如果新的閾值是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) {//取出當前的節點 eNode<K,V> e;//如果當前桶中有元素,則將鏈表賦值給eif ((e = oldTab[j]) != null) {//將原哈希桶置空以便GColdTab[j] = null;//如果當前鏈表中就一個元素,(沒有發生哈希碰撞)if (e.next == null)//直接將這個元素放置在新的哈希桶里。//注意這里取下標 是用 哈希值 與 桶的長度-1 。 由于桶的長度是2的n次方,這么做其實是等于 一個模運算。但是效率更高newTab[e.hash & (newCap - 1)] = e;//如果發生過哈希碰撞 ,而且是節點數超過8個,轉化成了紅黑樹else if (e instanceof TreeNode)((TreeNode<K,V>)e).split(this, newTab, j, oldCap);//如果發生過哈希碰撞,節點數小于8個。則要根據鏈表上每個節點的哈希值,依次放入新哈希桶對應下標位置。else { // preserve order//因為擴容是容量翻倍,所以原鏈表上的每個節點,現在可能存放在原來的下標,即low位, 或者擴容后的下標,即high位。 high位= low位+原哈希桶容量//低位鏈表的頭結點、尾節點Node<K,V> loHead = null, loTail = null;//高位鏈表的頭節點、尾節點Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;//臨時節點 存放e的下一個節點do {next = e.next;//這里又是一個利用位運算 代替常規運算的高效點: 利用哈希值 與 舊的容量,可以得到哈希值去模后,是大于等于oldCap還是小于oldCap,等于0代表小于oldCap,應該存放在低位,否則存放在高位if ((e.hash & oldCap) == 0) {//給頭尾節點指針賦值if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}//高位也是相同的邏輯else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}//循環直到鏈表結束} while ((e = next) != null);//將低位鏈表存放在原index處,if (loTail != null) {loTail.next = null;newTab[j] = loHead;}//將高位鏈表存放在新index處if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}return newTab;}

    https://blog.csdn.net/tuke_tuke/article/details/51588156?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

    HashSet

    對于HashSet而言,它是基于HashMap實現的,HashSet底層使用HashMap來保存所有元素,因此HashSet 的實現比較簡單.

    private transient HashMap<E,Object> map;// 默認的value值 private static final Object PRESENT = new Object();/*** 無參構造方法,默認容量16,loadfactory0.75*/ public HashSet() {map = new HashMap<>(); }/*** 構造方法,默認容量為大于參數容量的2.冪次方,loadfactory0.75*/ public HashSet(Collection<? extends E> c) {map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));addAll(c); }/*** 自定義容量和loadfactory*/ public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<>(initialCapacity, loadFactor); }/*** 自定義容量 loadfactory0.75*/ public HashSet(int initialCapacity) {map = new HashMap<>(initialCapacity); }/*** 自定義容量 loadfactory 和默認value*/ HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor); }/*** */ public boolean contains(Object o) {return map.containsKey(o); }/*** 講元素置為key*/ public boolean add(E e) {return map.put(e, PRESENT)==null; }

    ?

    BitSet

    Bitset是Java中的一種數據結構。Bitset中主要存儲的是二進制位,做的也都是位運算,每一位只用來存儲0,1值,主要用于對數據的標記,用1位來表示一個數據是否出現過,0為沒有出現過,1表示出現過。(非線程安全)

    使用場景:整數,無重復。

    參考文檔:https://blog.csdn.net/kongmin_123/article/details/82225172?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

    BitSet的底層實現是使用long數組作為內部存儲結構的,這就決定了BitSet至少為一個long的大小,而且BitSet的大小為long類型大小(64位)的整數倍。
    /** 位集被放到一個long型的數組中,由64位組成,需要6個地址位。*/ private final static int ADDRESS_BITS_PER_WORD = 6; private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;/* Used to shift left or right for a partial word mask */ private static final long WORD_MASK = 0xffffffffffffffffL;/*** @serialField bits long[]** The bits in this BitSet. The ith bit is stored in bits[i/64] at* bit position i % 64 (where bit position 0 refers to the least* significant bit and 63 refers to the most significant bit).*/ private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("bits", long[].class), };/*** 底層存儲結構*/ private long[] words;

    BitSet的構造函數有兩個,如果指定了初始化大小,那么會把他規整到一個大于或者等于這個數字的64的整倍數。比如64位,BitSet的大小是1個long,而65位時,指定了大小是2個long,即128位。做這么一個規定,主要是為了內存對齊,同時避免考慮到特殊情況的處理,簡化程序。

    public BitSet() {initWords(BITS_PER_WORD);sizeIsSticky = false; }public BitSet(int nbits) {// nbits不能為負;大小為0可以if (nbits < 0)throw new NegativeArraySizeException("nbits < 0: " + nbits);initWords(nbits);sizeIsSticky = true; }// 給定索引,返回新的數組private void initWords(int nbits) {words = new long[wordIndex(nbits-1) + 1]; }private static int wordIndex(int bitIndex) {return bitIndex >> ADDRESS_BITS_PER_WORD; }

    BitSet如何存儲數據?怎么快速定位他的存儲位置?

    BitSet的默認初始大小是一個long數組,一個long數組就是64個bit,每一個bit的值就是二進制的0或者1,bit的值和相應位置就代表一個數在不在BitSet當中,0代表該數值不存在,1代表該數組值存在。這樣就可以描述數據對數據進行標記了。

    ?

    在這里,0、3、63等存放入了long數組中。

    從上面的BitSet的結構圖我們可以看到,要想定位一個數據,需要確定兩個值:

    (1)這個數位于哪個數組,也就是確定words[wordIndex]?的wordIndex是多少。

    (2)這個數位于數組的哪一部分,也就是確定這個數的bitIndex是哪一位。

    public void set(int bitIndex) {// 傳入的下標是否越界if (bitIndex < 0)throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); // 判斷要存入的bitIndex應該在那個數組中int wordIndex = wordIndex(bitIndex); // 如果現有數組不能滿足,拓展大小expandTo(wordIndex); // 進行的邏輯運算,對1進行左移,然后與words[wordIndex]做或(or)運算。words[wordIndex] |= (1L << bitIndex); // Restores invariantscheckInvariants(); }

    BitSet的用法

    BitSet bitSet = new BitSet(); bitSet.set(50); // 位數 64 System.out.println(bitSet.size()); bitSet.set(130); // 位數 192 System.out.println(bitSet.size()); // 是否存在 boolean b = bitSet.get(130); System.out.println(b); // stream boolean match = bitSet.stream().anyMatch(bit -> Objects.equals(bit, 130)); System.out.println(match); // 清空所有bit位 清空某一位 clear(int bitIndex) bitSet.clear(); // 反轉 bitSet.flip(30);BitSet bitSet1 = new BitSet(); bitSet1.set(50); bitSet1.set(250); // 并集 bitSet1.or(bitSet); // 交集 bitSet.and(bitSet1); // 補集 bitSet.andNot(bitSet1);

    BitSet的應用:

    (1)大數據量的查找。

    (2)大數據量的去重。

    (3)大數據量的統計。

    (4)大數據量的排序。

    (5)求數據的并集、交集、補集等。

    (6)大數據量的判別。

    ? BitSet常見的應用是那些對海量數據進行一些統計工作,比如日志分析、用戶數統計等等。

    具體可參考:https://blog.csdn.net/kongmin_123/article/details/82257209

    三:接口及類詳解【GUAVA】

    https://blog.csdn.net/kuyuyingzi/article/details/30529053?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-5.channel_param

    BiMap接口

    繼承自:?java.util.Map;bimap(或“雙向映射”)是一種保持其值和鍵的唯一性的映射。此約束使bimap支持“反向視圖”,即另一個bimap,包含與此bimap相同的條目,但具有相反的鍵和值。 目前的實現類:EnumBiMap,?EnumHashBiMap,?HashBiMap,?ImmutableBiMap

    ?

    public class GuavaTester {public static void main(String args[]){BiMap<Integer, String> empIDNameMap = HashBiMap.create();empIDNameMap.put(new Integer(101), "Mahesh");empIDNameMap.put(new Integer(102), "Sohan");empIDNameMap.put(new Integer(103), "Ramesh");//Emp Id of Employee "Mahesh"System.out.println(empIDNameMap.inverse().get("Mahesh"));} 輸出結果:101

    ?

    Multiset

    Collection<E>,?Iterable<E>;支持順序獨立相等的集合,如Set,但可能有重復的元素。多套有時也被稱為包。多集合中彼此相等的元素被稱為同一個元素的出現。一個元素在multiset中出現的總數稱為該元素的計數(“frequency”和“multiplicity”這兩個術語是等價的,但在這個API中沒有使用)。由于元素的計數用int表示,因此multiset的值永遠不能超過Integer.MAX_值任何一個元素的出現。

    目前的實現類:ConcurrentHashMultiset,?EnumMultiset,?ForwardingMultiset,?ForwardingSortedMultiset,?ForwardingSortedMultiset.StandardDescendingMultiset,?HashMultiset,?ImmutableMultiset,?ImmutableSortedMultiset,?LinkedHashMultiset,?TreeMultiset

    ?

    public class GuavaTester {public static void main(String args[]){//create a multiset collectionMultiset<String> multiset = HashMultiset.create();multiset.add("a");multiset.add("b");multiset.add("c");multiset.add("d");multiset.add("a");multiset.add("b");multiset.add("c");multiset.add("b");multiset.add("b");multiset.add("b");//print the occurrence of an elementSystem.out.println("Occurrence of 'b' : "+multiset.count("b"));//print the total size of the multisetSystem.out.println("Total Size : "+multiset.size());//get the distinct elements of the multiset as setSet<String> set = multiset.elementSet();//display the elements of the setSystem.out.println("Set [");for (String s : set) { System.out.println(s); }System.out.println("]");//display all the elements of the multiset using iteratorIterator<String> iterator = multiset.iterator();System.out.println("MultiSet [");while(iterator.hasNext()){System.out.println(iterator.next());}System.out.println("]"); //display the distinct elements of the multiset with their occurrence countSystem.out.println("MultiSet [");for (Multiset.Entry<String> entry : multiset.entrySet()){System.out.println("Element: "+entry.getElement() +", Occurrence(s): " + entry.getCount()); }System.out.println("]"); //remove extra occurrences multiset.remove("b",2);//print the occurrence of an elementSystem.out.println("Occurence of 'b' : "+multiset.count("b"));} 輸出結果: Occurence of 'b' : 5 Total Size : 10 Set [ d b c a ] MultiSet [ d b b b b b c c a a ] MultiSet [ Element: d, Occurence(s): 1 Element: b, Occurence(s): 5 Element: c, Occurence(s): 2 Element: a, Occurence(s): 2 ] Occurence of 'b' : 3

    Multimaps

    ?

    提供作用于或生成多重映射的靜態方法。

    index

    作為Maps.uniqueIndex的兄弟方法,Multimaps.index(Iterable, Function)通常針對的場景是:有一組對象,它們有共同的特定屬性,我們希望按照這個屬性的值查詢對象,但屬性值不一定是獨一無二的。比方說,我們想把字符串按長度分組。

    ImmutableSet digits = ImmutableSet.of("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine");Function<String, Integer> lengthFunction = new Function<String, Integer>() {public Integer apply(String string) {return string.length();} }; ImmutableListMultimap<Integer, String> digitsByLength= Multimaps.index(digits, lengthFunction); /* * digitsByLength maps: * 3 => {"one", "two", "six"} * 4 => {"zero", "four", "five", "nine"} * 5 => {"three", "seven", "eight"} */

    invertFrom

    鑒于Multimap可以把多個鍵映射到同一個值(譯者注:實際上這是任何map都有的特性),也可以把一個鍵映射到多個值,反轉Multimap也會很有用。Guava 提供了invertFrom(Multimap toInvert,
    Multimap dest)做這個操作,并且你可以自由選擇反轉后的Multimap實現。

    注:如果你使用的是ImmutableMultimap,考慮改用ImmutableMultimap.inverse()做反轉。

    ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create(); multimap.putAll("b", Ints.asList(2, 4, 6)); multimap.putAll("a", Ints.asList(4, 2, 1)); multimap.putAll("c", Ints.asList(2, 5, 3)); TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap<String, Integer>.create()); //注意我們選擇的實現,因為選了TreeMultimap,得到的反轉結果是有序的 /* * inverse maps: * 1 => {"a"} * 2 => {"a", "b", "c"} * 3 => {"c"} * 4 => {"a", "b"} * 5 => {"c"} * 6 => {"b"} */

    forMap

    想在Map對象上使用Multimap的方法嗎?forMap(Map)把Map包裝成SetMultimap。這個方法特別有用,例如,與Multimaps.invertFrom結合使用,可以把多對一的Map反轉為一對多的Multimap。

    Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2); SetMultimap<String, Integer> multimap = Multimaps.forMap(map); // multimap:["a" => {1}, "b" => {1}, "c" => {2}] Multimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap<Integer, String>.create()); // inverse:[1 => {"a","b"}, 2 => {"c"}]

    Table

    Table代表一個特殊的映射,其中兩個鍵可以在組合的方式被指定為單個值。它類似于創建映射的映射。

    ?

    public class GuavaTester {public static void main(String args[]){//Table<R,C,V> == Map<R,Map<C,V>>/** Company: IBM, Microsoft, TCS* IBM -> {101:Mahesh, 102:Ramesh, 103:Suresh}* Microsoft -> {101:Sohan, 102:Mohan, 103:Rohan } * TCS -> {101:Ram, 102: Shyam, 103: Sunil } * * *///create a tableTable<String, String, String> employeeTable = HashBasedTable.create();//initialize the table with employee detailsemployeeTable.put("IBM", "101","Mahesh");employeeTable.put("IBM", "102","Ramesh");employeeTable.put("IBM", "103","Suresh");employeeTable.put("Microsoft", "111","Sohan");employeeTable.put("Microsoft", "112","Mohan");employeeTable.put("Microsoft", "113","Rohan");employeeTable.put("TCS", "121","Ram");employeeTable.put("TCS", "122","Shyam");employeeTable.put("TCS", "123","Sunil");//get Map corresponding to IBMMap<String,String> ibmEmployees = employeeTable.row("IBM");System.out.println("List of IBM Employees");for(Map.Entry<String, String> entry : ibmEmployees.entrySet()){System.out.println("Emp Id: " + entry.getKey() + ", Name: " + entry.getValue());}//get all the unique keys of the tableSet<String> employers = employeeTable.rowKeySet();System.out.print("Employers: ");for(String employer: employers){System.out.print(employer + " ");}System.out.println();//get a Map corresponding to 102Map<String,String> EmployerMap = employeeTable.column("102");for(Map.Entry<String, String> entry : EmployerMap.entrySet()){System.out.println("Employer: " + entry.getKey() + ", Name: " + entry.getValue());} } }輸出: List of IBM Employees Emp Id: 102, Name: Ramesh Emp Id: 101, Name: Mahesh Emp Id: 103, Name: Suresh Employers: IBM TCS Microsoft Employer: IBM, Name: Ramesh

    四:常用API及原理解析

    常用API

    Map常用API

    HashMap<String, String> map6 = Maps.newHashMap(); // 如果不存在則存入 map6.putIfAbsent("one", "1"); map6.putIfAbsent("one", "2"); // 存在覆蓋,不存在存入 map6.put("one","3"); map6.put("two", "2"); // 根據給出的function計算value map6.compute("three", (x, y) -> x + y + "compute"); map6.computeIfPresent("two",(x,y) -> x + y + "compute1"); map6.computeIfAbsent() // 根據key和funtion對value進行merge map6.merge("one", "8", (x, y) -> x + y);

    集合常用API

    List<YearMonthBo> yearMonthBoList = Lists.newArrayList(); // 根據給定的方式移除元素,有元素移除返回true,可以為空,不可以為null,注意源碼移除方式,用其他循環代替是否可行? boolean isRemove = yearMonthBoList.removeIf(x -> Objects.nonNull(x)); yearMonthBoList.add(new YearMonthBo(2020, 11)); yearMonthBoList.add(new YearMonthBo(2020, 12)); yearMonthBoList.add(new YearMonthBo(2020, 11)); yearMonthBoList.add(new YearMonthBo(2019, 11)); // 根據給定排序方式排序,可以為空,不可以為null yearMonthBoList.sort(Comparator.comparing(YearMonthBo::getMonth)); // 添加集合元素,可以為空,不可以為null yearMonthBoList.addAll(Lists.newArrayList(new YearMonthBo(2020,6))); yearMonthBoList.add(new YearMonthBo(2020,4)); // get set remove foreach size indexOf等方法不再贅述

    Stack常用API

    // stack繼承vector,實現了List接口,有List接口所有功能 Stack<String> stack = new Stack<>(); // 放入一個元素 stack.push("a"); // 彈出元素 String pop = stack.pop(); // 取棧頂元素 String peek = stack.peek();

    Queue常用API

    // 隊列先進先出 Queue<String> queue = new ArrayBlockingQueue<String>(10); // 添加元素 queue.offer("a"); queue.offer("b"); // 隊列頭部元素 String peek = queue.peek(); // 取出隊列頭部元素 String poll = queue.poll();


    常見集合處理方式

    guava集合交集,差集,并集

    Set<Integer> sets = Sets.newHashSet(1, 2, 3, 4, 5, 6);Set<Integer> sets2 = Sets.newHashSet(3, 4, 5, 6, 7, 8, 9);// 交集System.out.println("交集為:");SetView<Integer> intersection = Sets.intersection(sets, sets2);for (Integer temp : intersection) {System.out.println(temp);}// 差集System.out.println("差集為:");SetView<Integer> diff = Sets.difference(sets, sets2);for (Integer temp : diff) {System.out.println(temp);}// 并集System.out.println("并集為:");SetView<Integer> union = Sets.union(sets, sets2);for (Integer temp : union) {System.out.println(temp);}

    java集合交集,差集,并集

    public static void main(String[] args) {List<String> list1 = new ArrayList<String>();list1.add("A");list1.add("B");list1.add("C");List<String> list2 = new ArrayList<String>();list2.add("C");list2.add("B");list2.add("D");// 并集list1.addAll(list2);// 去重復并集list2.removeAll(list1);list1.addAll(list2);// 交集list1.retainAll(list2);// 差集list1.removeAll(list2); }

    Stream流取并集的幾種方式

    List<YearMonthBo> list1 = new ArrayList<YearMonthBo>(); list1.add(new YearMonthBo(2020, 1)); list1.add(new YearMonthBo(2020, 2)); list1.add(new YearMonthBo(2019, 12));List<YearMonthBo> list2 = new ArrayList<YearMonthBo>(); list2.add(new YearMonthBo(2020, 2)); list2.add(new YearMonthBo(2020, 3)); list2.add(new YearMonthBo(2019, 11)); // 1:集合并集 List<YearMonthBo> collect = Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toList()); // 2:去重取并集 Set<YearMonthBo> collect1 = Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toSet()); // 3:合并去重 List<YearMonthBo> collect2 = Stream.of(list1, list2).flatMap(List::stream).distinct().collect(Collectors.toList()); // 4:合并并根據對象中的某些字段去重(相乘相加等操作均可) ArrayList<YearMonthBo> yearMonthBoArrayList = Lists.newArrayList(Stream.of(list1, list2).flatMap(List::stream).collect(Collectors.toMap(YearMonthBo::getYear, Function.identity(), (x, y) -> x == null ? y : x)).values()); // 5:集合合并 List<YearMonthBo> collect3 = Stream.concat(list1.stream(), list2.stream()).collect(Collectors.toList());

    集合排序

    // 1:根據compare接口排序,需實現Comparable接口 Collections.sort(testList); // 2:根據自定義比較器排序 Collections.sort(testList, YearMonthBo::compareTo); // 3:根據自定義排序器排序 testList.sort(Comparator.comparingInt(YearMonthBo::getYear));

    集合 轉換為map

    // collectors方法 tomap Map<Integer, YearMonthBo> map2 = testList.stream().collect(Collectors.toMap(YearMonthBo::getYear, Function.identity(), (a1, a2) -> new YearMonthBo(a1.getYear() + a2.getYear(), a2.getMonth() + a1.getMonth()))); // collectors方法 grouping by Map<Integer, List<YearMonthBo>> map3 = testList.stream().collect(Collectors.groupingBy(YearMonthBo::getYear)); // guava tomap Map<Integer, YearMonthBo> map1 = Maps.uniqueIndex(testList, YearMonthBo::getYear);

    集合去重

    List<YearMonthBo> list1 = new ArrayList<YearMonthBo>(); list1.add(new YearMonthBo(2020, 1)); list1.add(new YearMonthBo(2020, 2)); list1.add(new YearMonthBo(2019, 12));List<YearMonthBo> list2 = new ArrayList<YearMonthBo>(); list2.add(new YearMonthBo(2020, 2)); list2.add(new YearMonthBo(2020, 3)); list2.add(new YearMonthBo(2019, 11)); // 1:根據equals和hashcode去重 List<YearMonthBo> collect4 = Stream.of(list1, list2).flatMap(List::stream).distinct().collect(Collectors.toList()); // 2:”根據對象屬性去重 Collection<YearMonthBo> values = Stream.of(list1).flatMap(List::stream).collect(Collectors.toMap(YearMonthBo::getYear, Function.identity(), (x, y) -> x == null ? y : x)).values(); // 3:根據對象屬性去重 List<YearMonthBo> collect5 = Stream.of(list1, list2).flatMap(List::stream).filter(distinctByKey(YearMonthBo::getYear)).collect(Collectors.toList());


    集合反轉

    public static void main(String[] args) {List<String> list1 = Lists.newArrayList("a","b","c");List<String> list2 = new ArrayList<String>();list2.add("C");list2.add("B");list2.add("D");// guava反轉Lists.reverse(list1 );// java反轉for循環反轉 }

    笛卡爾積

    HashSet<Integer> set = Sets.newHashSet(1, 4, 3); HashSet<Integer> set1 = Sets.newHashSet(1, 9, 8); Set<List<Integer>> lists = Sets.cartesianProduct(set, set1); System.out.println(lists);

    字符串集合拼接(空分隔符,帶分隔符,帶分隔符和前綴后綴)

    List<String> strList = new ArrayList<>(); strList.addAll(Lists.newArrayList("aa", "vv", "ww")); String collect = strList.stream().collect(Collectors.joining()); String collect = strList.stream().collect(Collectors.joining(",")); String collect = strList.stream().collect(Collectors.joining(",","prefix","suffix"));

    初始化

    java集合初始化

    序號初始化方式備注
    1 ArrayList<String> objects1 = new ArrayList<>(); ?
    2 ArrayList<String> objects1 = new ArrayList<>(cap); ?
    3 ArrayList<String> objects1 = new ArrayList<>(Collection); ?

    guava集合初始化

    序號初始化方式備注
    1 HashSet<Integer> integers = Sets.newHashSet(1, 2, 4); 自動識別泛型類型
    2 HashSet<Object> objects = Sets.newHashSet(); ?
    3 Sets.newHashSetWithExpectedSize(5); ?
    4 Sets.newHashSet(Itearable); ?

    紅黑樹

    簡介:

    紅黑樹是一種自平衡排序二叉樹,樹中每個節點的值,都大于或等于在它的左子樹中的所有節點的值,并且小于或等于在它的右子樹中的所有節點的值,這確保紅黑樹運行時可以快速地在樹中查找和定位的所需節點,是一種特殊的排序二叉樹。

    ? ? 排序二叉樹要么是一棵空二叉樹,要么是具有下列性質的二叉樹:

    ? ? ? ? 若它的左子樹不空,則左子樹上所有節點的值均小于它的根節點的值;

    ? ? ? ? 若它的右子樹不空,則右子樹上所有節點的值均大于它的根節點的值;

    ? ? ? ? 它的左、右子樹也分別為排序二叉樹。

    排序二叉樹的構成:每當程序希望添加新節點時:系統總是從樹的根節點開始比較 ,即將根節點當成當前節點,如果新增節點大于當前節點、并且當前節點的右子節點存在,則以右子節點作為當前節點;如果新增節點小于當前節點、并且當前節點的左子節點存在,則以左子節點作為當前節點;如果新增節點等于當前節點,則用新增節點覆蓋當前節點,并結束循環 —— 直到找到某個節點的左、右子節點不存在,將新節點添加該節點的子節點 —— 如果新節點比該節點大,則添加為右子節點;如果新節點比該節點小,則添加為左子節點。

    紅黑樹的定義:

    ? ? 性質 1:每個節點要么是紅色,要么是黑色。

    ? ? 性質 2:根節點永遠是黑色的。

    ? ? 性質 3:所有的葉節點都是空節點(即 null),并且是黑色的。

    ? ? 性質 4:每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的路徑上不會有兩個連續的紅色節點)

    ? ? 性質 5:從任一節點到其子樹中每個葉子節點的路徑都包含相同數量的黑色節點。

    根據性質 5:紅黑樹從根節點到每個葉子節點的路徑都包含相同數量的黑色節點,因此從根節點到葉子節點的路徑中包含的黑色節點數被稱為樹的“黑色高度(black-height)”。

    性質 4 則保證了從根節點到葉子節點的最長路徑的長度不會超過任何其他路徑的兩倍。假如有一棵黑色高度為 3 的紅黑樹:從根節點到葉節點的最短路徑長度是 2,該路徑上全是黑色節點(黑節點 - 黑節點 - 黑節點)。最長路徑也只可能為 4,在每個黑色節點之間插入一個紅色節點(黑節點 - 紅節點 - 黑節點 - 紅節點 - 黑節點),性質 4 保證絕不可能插入更多的紅色節點。由此可見,紅黑樹中最長路徑就是一條紅黑交替的路徑。由此我們可以得出結論:對于給定的黑色高度為 N 的紅黑樹,從根到葉子節點的最短路徑長度為 N-1,最長路徑長度為 2 * (N-1)。

    提示:排序二叉樹的深度直接影響了檢索的性能,正如前面指出,當插入節點本身就是由小到大排列時,排序二叉樹將變成一個鏈表,這種排序二叉樹的檢索性能最低:N 個節點的二叉樹深度就是 N-1。

    紅黑樹通過上面這種限制來保證它大致是平衡的——因為紅黑樹的高度不會無限增高,這樣保證紅黑樹在最壞情況下都是高效的,不會出現普通排序二叉樹的情況。

    由于紅黑樹只是一個特殊的排序二叉樹,因此對紅黑樹上的只讀操作與普通排序二叉樹上的只讀操作完全相同,只是紅黑樹保持了大致平衡,因此檢索性能比排序二叉樹要好很多。

    但在紅黑樹上進行插入操作和刪除操作會導致樹不再符合紅黑樹的特征,因此插入操作和刪除操作都需要進行一定的維護,以保證插入節點、刪除節點后的樹依然是紅黑樹。

    插入節點后的修復

    ?

    刪除節點后的修復

    五:實踐

    集合使用規范

    集合對比

    名稱是否有序是否允許重復線程安全是否可以為空特性備注
    ArrayList有序不安全可以??
    LinkList有序不安全可以??
    HashSet無序不安全可以??
    TreeSet有序不安全不可以??
    HashMap無序Key唯一 value可重復不安全key value均可以??
    TreeMap有序Key唯一 value可重復不安全value可以 key不可以??
    HashTable無序Key唯一 value可重復安全不可以??

    ConcurrentHashMap

    無序Key唯一 value可重復安全不可以??
    Vector有序安全可以??
    ???????

    區別與適用場景:

    ? ? Set和List對比:?
    ? ??? ??Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。

    ? ? ? ??適用場景:頻繁對集合元素進行增刪操作的場景;需要保證數據不重復的場景。

    ? ??? ??List:和數組類似,List可以動態增長,查找元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變。?

    ?? ? ? ?適用場景:查詢較為頻繁的場景;元素可重復;需在確定索引上進行增刪操作的場景。

    ? ? ArrayList和LinkList的對比:

    ????? ? ArrayList: 隨機訪問get和set優于linklist,因為linklist要移動指針。

    ? ? ??? LinkList:對于add和remove操作優于arraylist,因為arraylist要移動數據。(一般情況下)

    利用set集合去重

    /*** 獲取對應三級部門下的采購員*/ public Set<PurchaserVo> getPurControllerByDept(Integer deptId3) {// 根據三級部門獲取采購/銷售/部門/品牌/品類關系List<CateBrandPurSalerRelVo> relVoList = sccAuthJsfService.getCateBrandPurSalerRelByDept3(deptId3);// 部門下不存在權限關系則記錄異常日志,返回空關系集合if (CollectionUtils.isEmpty(relVoList)) {log.error("三級部門:{}下權限關系數據為空!", deptId3);return Collections.emptySet();}// 將權限關系放到set集合中,自動去重Set<PurchaserVo> purchaserVoSet = Sets.newHashSet();relVoList.forEach(relVo -> {PurchaserVo purchaserVo = new PurchaserVo();purchaserVo.setPurchaserErp(relVo.getPurchaserControlErp());purchaserVo.setPurchaserName(relVo.getPurchaserControlName());purchaserVoSet.add(purchaserVo);});return purchaserVoSet; }

    排序,去重,根據某字段排序

    /*** 合并去重排序*/ private List<CommonDropdownDto> unionAndDistinct2List(List<CommonDropdownDto> purDataList,List<CommonDropdownDto> purDataInDb) {return Stream.concat(purDataList.stream(), purDataInDb.stream()).distinct().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getValue()))),ArrayList::new)); }

    集合轉換MAP

    集合轉換為map時可以使用Collectors類中的toMap方法,但是需要注意,如果有重復的鍵或者值時,會拋出異常。需自己傳入處理重復的方法。 (也可轉換為線程安全的map :toConcurrentMap)

    也可以使用GroupingBy進行分組。

    List<YearMonthBo> yearMonthBoList = Lists.newArrayList(); yearMonthBoList.add(new YearMonthBo(2020, 11)); yearMonthBoList.add(new YearMonthBo(2020, 12)); yearMonthBoList.add(new YearMonthBo(2020, 11)); // Exception in thread "main" java.lang.IllegalStateException: Duplicate key 11 Map<YearMonthBo, Integer> map1 = yearMonthBoList.stream().collect(Collectors.toMap(Function.identity(), YearMonthBo::getMonth)); // success Map<YearMonthBo, Integer> map2 = yearMonthBoList.stream().collect(Collectors.toMap(Function.identity(), YearMonthBo::getMonth, Integer::sum)); // success Map<Integer, List<YearMonthBo>> map4 = yearMonthBoList.stream().collect(Collectors.groupingBy(yearMonthBo -> yearMonthBo.getYear()));

    ?

    總結

    以上是生活随笔為你收集整理的JAVA集合和guava集合使用和原理解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    成人免费看电影 | 97国产大学生情侣酒店的特点 | 视频91| 亚洲另类视频在线 | 久久久久综合 | 91在线免费公开视频 | 日韩精品一区二区三区丰满 | 永久免费av在线播放 | 免费国产视频 | 中国一级特黄毛片大片久久 | 国产免费又黄又爽 | 狠狠干在线播放 | 欧美精品免费视频 | 久久综合99| 91一区二区三区在线观看 | 亚州欧美精品 | 国产美女网 | 亚洲做受高潮欧美裸体 | 日韩三级免费 | 丰满少妇在线观看网站 | 黄色免费看片网站 | 久草综合在线观看 | 中文国产成人精品久久一 | 欧美特一级片 | 最近中文字幕大全中文字幕免费 | 免费欧美 | 欧美日韩精品在线 | 91天堂在线观看 | 欧日韩在线视频 | 亚洲欧洲一级 | 88av色| 在线成人免费av | 91精品国产一区 | 在线一二三区 | 少妇性bbb搡bbb爽爽爽欧美 | 麻豆播放 | 激情视频久久 | 精品国产色 | 在线观看www.| 久久久美女 | 成人午夜剧场在线观看 | av三级av| 国产在线精品国自产拍影院 | 亚洲国产精品va在线看黑人 | 欧美天天综合网 | 热久久这里只有精品 | 日日夜夜天天久久 | 免费黄在线看 | 久久色网站 | 99久高清在线观看视频99精品热在线观看视频 | 国产精品久久网 | 亚洲天堂精品视频在线观看 | 久久国内免费视频 | 欧美日韩国产综合网 | 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | 午夜 在线 | 在线观看亚洲精品 | 天堂视频中文在线 | 亚洲婷婷伊人 | 色鬼综合网 | 国产福利不卡视频 | 亚州天堂| 亚洲在线高清 | 99视频精品视频高清免费 | 在线一区电影 | 日韩一三区 | 在线国产中文字幕 | 97香蕉久久国产在线观看 | 免费视频黄色 | 成年人视频在线免费观看 | 午夜影院日本 | 在线观看国产永久免费视频 | 日日干av| 国产免费观看高清完整版 | 国产精品久久麻豆 | 99久久精品免费看国产一区二区三区 | 国产一级黄大片 | 中文av一区二区 | 亚洲精品xxx| 成人av在线资源 | 91久久久久久国产精品 | 四虎永久精品在线 | 午夜美女网站 | 91久久一区二区 | 亚州精品天堂中文字幕 | 天堂素人在线 | 日精品在线观看 | 在线观看911视频 | 国产成人精品aaa | 日韩av免费大片 | 麻豆一二 | 在线观看av麻豆 | 欧洲亚洲女同hd | 成人久久综合 | 丁香六月五月婷婷 | 九九三级毛片 | 久久天天躁狠狠躁亚洲综合公司 | 亚洲精品国产精品乱码在线观看 | 亚洲黄污| 欧亚日韩精品一区二区在线 | 国产在线一区二区三区播放 | 免费观看视频的网站 | 精品一区二区电影 | 国产免费av一区二区三区 | 久国产在线播放 | 婷婷成人综合 | 91九色porny在线 | 国产在线最新 | 超碰在线最新网址 | 在线免费中文字幕 | 中日韩在线视频 | 久久久久久久久久久影视 | 91在线一区二区 | 在线欧美日韩 | 免费看一级一片 | 国产91粉嫩白浆在线观看 | 中文字幕观看av | 中字幕视频在线永久在线观看免费 | 99情趣网视频 | 日韩高清片 | 激情综合网五月婷婷 | 精品国产乱码久久久久久1区2匹 | 久久久久久蜜桃一区二区 | 久久免费成人 | av日韩av| 国产中文字幕亚洲 | 久久久99精品免费观看乱色 | 亚洲a免费 | 国产精品一区在线播放 | 久久中文视频 | 免费国产ww| 亚洲麻豆精品 | 亚洲国产日韩av | 久久婷亚洲五月一区天天躁 | 超碰免费av | 337p日本欧洲亚洲大胆裸体艺术 | 97综合视频 | 国产h在线播放 | 欧美一区二区在线 | 国产精品美女久久久久久久 | 不卡的av在线| 久草在在线视频 | 国产伦理久久精品久久久久_ | 开心激情久久 | 久久综合久久鬼 | 91chinese在线| 在线播放 亚洲 | 国产精品短视频 | 欧美夫妻生活视频 | 欧美一二三在线 | 韩日视频在线 | 成人h在线 | 日本视频高清 | 在线视频观看成人 | 亚洲少妇xxxx| 久草视频中文在线 | 婷婷丁香久久五月婷婷 | 亚洲电影免费 | 久久99中文字幕 | 国产aaa毛片| 婷婷视频 | 久久久首页 | 免费av在线网| 亚洲精品视频在线免费 | 成人午夜电影在线观看 | 麻豆视频在线播放 | 日韩免费在线一区 | 成年人免费看av | 久久精彩免费视频 | 青青视频一区 | 久久久久福利视频 | 日本一区二区免费在线观看 | 日本中文不卡 | 日韩中文字 | 国产精品久久久久久久久久久久久 | 综合色亚洲 | 99在线精品视频在线观看 | 国产成人一区二区三区久久精品 | 在线视频免费观看 | 国产五码一区 | 丁香激情综合久久伊人久久 | 精品视频中文字幕 | 玖玖在线看 | 国产在线精品一区二区三区 | 国产最新在线观看 | 国产一区 在线播放 | 91看片淫黄大片一级在线观看 | 人人看看人人 | 色综合色综合色综合 | 精品国产免费一区二区三区五区 | 又黄又爽又刺激的视频 | 天天插天天 | 深夜国产在线 | 免费日韩视 | 91麻豆精品久久久久久 | 久久久av电影 | 日韩免费播放 | 日日碰狠狠躁久久躁综合网 | 久久草精品 | 亚州精品天堂中文字幕 | 久久精品中文字幕免费mv | 国产精品久久久久久久久久ktv | 亚洲国产欧洲综合997久久, | 天天色综合天天 | 黄色av大片 | 超碰在线9| 天天天天综合 | 久久久免费精品视频 | 国产一区二区在线免费观看 | 又污又黄的网站 | a级成人毛片 | 狠狠色丁香婷婷综合最新地址 | 人人爱人人添 | 又黄又爽又刺激视频 | 免费av一级电影 | 亚洲欧美日韩一二三区 | 国产精品久久一区二区三区, | 国产在线播放一区 | 麻豆视频免费观看 | 成人h动漫精品一区二 | 丰满少妇在线 | 国产一区二区精品久久91 | av在线永久免费观看 | 国产 欧美 日产久久 | 草久视频在线 | 91成人在线观看高潮 | 亚洲精品一区二区三区在线观看 | 日韩在线视频网站 | 亚洲综合视频在线观看 | 中文字幕一区二区三区在线视频 | 国产精品露脸在线 | 婷婷去俺也去六月色 | 久久久精品国产免费观看同学 | 日韩视频www | 国产精品成人一区 | 久久久国产一区 | 婷婷五天天在线视频 | 中文有码在线 | 成人黄在线观看 | 少妇高潮冒白浆 | 日韩理论片 | 日韩有码第一页 | 欧美精品久久久久 | 久久精品视频一 | 色综合天天综合 | 日日夜夜操av | 婷婷六月在线 | 久久精品久久99精品久久 | 亚洲国产中文字幕在线观看 | 九九视频在线观看视频6 | 丁香婷婷综合网 | 四虎天堂| 久久免费视频这里只有精品 | 天天曰天天爽 | 国产日产欧美在线观看 | 欧美大香线蕉线伊人久久 | 日本亚洲国产 | 色噜噜在线观看 | 精品99在线观看 | 激情综合网天天干 | 福利视频 | 国产不卡在线观看 | 中文在线免费看视频 | 中文在线免费看视频 | 亚洲午夜精品一区二区三区电影院 | 美女黄频网站 | 毛片美女网站 | 成人黄色av网站 | 日本三级全黄少妇三2023 | 天天搞天天| 国产91在线 | 美洲 | 激情欧美网 | 日韩免费高清 | 亚洲精品久久久久58 | 日韩精品不卡在线观看 | 久久国产片 | 日韩一区二区三区高清在线观看 | 91精品免费在线观看 | 国产在线观看一区 | 一级片免费在线 | 国产黄色片免费 | 欧美一二三区播放 | 精品一区欧美 | 在线观看视频免费播放 | 久久视频精品在线观看 | 国产三级午夜理伦三级 | 天天看天天干天天操 | 亚洲电影av在线 | 天天干天天想 | www.狠狠操.com | 国产婷婷vvvv激情久 | 日韩欧美一区二区三区免费观看 | 精品在线播放 | 日韩av在线看| 精品一区电影 | 欧美日韩一区二区三区免费视频 | 在线观看黄色小视频 | 日批网站在线观看 | 日韩视频在线观看视频 | 亚洲精品在线视频网站 | 黄色小说在线免费观看 | 精品免费一区 | 久草综合视频 | 97人人模人人爽人人喊网 | 亚洲精品videossex少妇 | 爱射综合| 黄色网址中文字幕 | 伊人狠狠色 | 久久国产精品久久精品 | 久久er99热精品一区二区三区 | 五月婷婷丁香六月 | 日韩精品视频一二三 | 91免费国产在线观看 | 日日干夜夜干 | 精品久久久久亚洲 | 人人干狠狠干 | 人人爽人人av | 欧美午夜激情网 | 夜夜爱av | 永久黄网站色视频免费观看w | 91九色在线视频 | 99热亚洲精品 | 韩国av免费观看 | 人人澡人人爽欧一区 | 久久欧洲视频 | 国产精品一区二区av | 久久99精品久久只有精品 | 国产一区二区精品91 | 又黄又爽又无遮挡的视频 | 久久久久久免费视频 | 99热这里只有精品国产首页 | 日韩欧美电影在线 | 国产精品午夜久久 | 午夜久久久久久久久久久 | www视频免费在线观看 | 在线播放亚洲 | 在线播放亚洲激情 | 免费久久精品视频 | 国产区久久 | 涩涩网站在线看 | 日韩网站在线看片你懂的 | 91网址在线看 | 久久伦理 | 97超碰.com | 国产成人精品一区二区三区在线 | 91精品久久久久久久91蜜桃 | 成人免费视频网站在线观看 | 在线观看视频日韩 | 久草网视频在线观看 | 色播五月婷婷 | 最新av网址在线观看 | 色播激情五月 | 波多野结衣视频一区 | av再线观看 | 黄色成人av在线 | 日日天天狠狠 | 少妇高潮冒白浆 | 国产 一区二区三区 在线 | 日韩av中文在线观看 | 99精品视频免费观看 | 国产精华国产精品 | 四虎永久网站 | 成人动漫一区二区三区 | 密桃av在线 | 国产91在 | 午夜精品一二三区 | 九九九电影免费看 | 亚洲影音先锋 | 开心色激情网 | 黄色国产高清 | 亚洲成av人片在线观看无 | 色欧美日韩 | www.玖玖玖 | 99精品国产福利在线观看免费 | 四虎影视精品 | 免费视频一二三区 | 在线免费精品视频 | 日韩深夜在线观看 | 亚州成人av在线 | 很黄很色很污的网站 | 国产午夜在线 | 精品国产亚洲日本 | www.黄色在线 | 亚洲在线a | 国产精品亚洲成人 | 久久99深爱久久99精品 | 国产精品99视频 | 免费精品国产 | av福利在线 | 九九热视频在线播放 | 黄色软件视频大全免费下载 | 成年人在线看片 | 久久经典国产视频 | 午夜狠狠操 | 久久精品96 | 五月天色丁香 | 国产91精品看黄网站在线观看动漫 | 可以免费观看的av片 | 成人在线免费av | 欧美日韩在线视频免费 | 天天操月月操 | 97人人澡人人爽人人模亚洲 | 国产黄a三级三级三级三级三级 | 久久久久久国产一区二区三区 | 三级黄色在线 | 又黄又爽的视频在线观看网站 | 黄a网站 | 黄色小网站在线 | 97超碰人人澡人人爱学生 | 最近中文字幕免费视频 | 久久国产网站 | 伊人婷婷| 在线观看黄网站 | 免费成人在线观看视频 | 这里只有精品视频在线观看 | 精久久久久 | 美女久久久久久久 | 四虎国产免费 | 国产精品wwwwww | 黄色99视频 | 91视频3p| 中文国产成人精品久久一 | 在线中文字幕观看 | 91精品1区2区| 日本韩国精品一区二区在线观看 | 日韩综合一区二区三区 | 在线观看av麻豆 | 国产一区二区三区免费在线 | 午夜aaaa | 手机在线黄色网址 | 日韩成人免费电影 | 国内99视频| 午夜精品久久久久久久久久久久 | 1024久久| 日韩电影精品 | 亚洲砖区区免费 | 伊人一级| 一区二区久久久久 | 国语精品免费视频 | 亚洲高清视频在线 | 亚洲欧洲一区二区在线观看 | 欧美资源在线观看 | 国产精品女人久久久 | 色中文字幕在线观看 | 日韩视频在线一区 | 又爽又黄在线观看 | av天天在线观看 | 一区二区三区在线看 | 玖玖国产精品视频 | 日韩精品视频免费专区在线播放 | 免费一级片在线 | 日本久久99 | 在线播放 日韩专区 | 91九色porny蝌蚪主页 | 国产99久久精品一区二区300 | 91成人免费在线视频 | 天天玩天天干天天操 | 国产精品免费在线 | 爱干视频 | 麻豆视频免费看 | 国产青青青 | 97热在线观看 | 日本在线视频网址 | 视频91在线 | 国产99久久九九精品免费 | 欧美极品久久 | 亚洲天堂社区 | 美女网色 | 97视频在线免费观看 | 欧美日韩久 | 日韩免费视频观看 | 97天天综合网 | 69精品视频在线观看 | 亚洲,播放 | 国精产品永久999 | 午夜色大片在线观看 | 中文字幕之中文字幕 | 久久精品高清视频 | 蜜臀av性久久久久av蜜臀妖精 | 国产一二三四在线观看视频 | 久久免费视屏 | 久久精品一区二区三区四区 | 精品福利网站 | 日黄网站 | 亚洲午夜久久久影院 | 91av播放 | 亚洲 欧美 变态 国产 另类 | 亚洲成人在线免费 | 国产精品视频永久免费播放 | 色中色资源站 | 免费日韩 | 国产一区二区精品在线 | 欧美a√在线 | 国产精品久久9 | 91超国产 | 高清av网 | 五月婷婷激情综合网 | 青草视频免费观看 | av电影亚洲 | 亚洲精品97 | 日韩午夜电影院 | 国产成人a v电影 | 日韩视频在线不卡 | 五月婷影院 | 国产精品对白一区二区三区 | 99久久国产免费,99久久国产免费大片 | 久久综合中文色婷婷 | 激情久久伊人 | 91久久国产自产拍夜夜嗨 | 国产一级91 | 91中文字幕网 | 91大神精品视频在线观看 | 女人高潮一级片 | 91香蕉亚洲精品 | 国产不卡免费 | 91av在线免费播放 | 玖玖国产精品视频 | 五月天天色 | 国产第一福利网 | 精品免费一区二区三区 | 这里只有精品视频在线 | 天天射天天操天天 | 久久久久久欧美二区电影网 | 999电影免费在线观看2020 | 午夜久久久影院 | 国产真实精品久久二三区 | 在线激情影院一区 | 99国产情侣在线播放 | 国产黄色a | 久久久久久久久久久电影 | 国产精品18久久久久久久久 | 国产97在线看 | 黄色毛片视频免费观看中文 | 亚洲精品乱码久久 | 人人藻人人澡人人爽 | 国产在线观看,日本 | 久久久影视 | 欧美日bb| 日韩在线中文字幕视频 | 波多野结衣网址 | 婷婷视频在线播放 | 久久国产视频网站 | 最近中文字幕免费观看 | 久久99久久99精品免观看软件 | 人人爽人人爽人人片av | 免费黄色网址大全 | 国产又粗又长又硬免费视频 | 女女av在线 | 亚洲日本欧美 | 9在线观看免费高清完整 | 一区二区三区在线观看免费视频 | 国产婷婷视频在线 | 国产专区免费 | 国产精品免费小视频 | 国产麻豆成人传媒免费观看 | 又黄又刺激的网站 | 久久国产日韩 | 亚洲黄色在线观看 | 亚洲精品久久久久久久蜜桃 | 91亚洲精品久久久久图片蜜桃 | 一区二区视频在线看 | 91精品啪| 国产中文字幕av | 国产亚洲视频系列 | 成人免费视频a | 天天操天天综合网 | 成人综合婷婷国产精品久久免费 | 国产日产精品一区二区三区四区 | 伊人久久五月天 | 色999精品 | 亚洲六月丁香色婷婷综合久久 | www.av在线播放 | 久久九九免费 | 国产视频久| 国产三级国产精品国产专区50 | 中文字幕乱码亚洲精品一区 | 97视频在线观看网址 | 国产精品12 | 91中文字幕网 | 精品在线免费视频 | 免费在线观看av片 | 免费成人av网站 | 国产黄a三级三级 | 久久精品日产第一区二区三区乱码 | 久久久久草 | 在线影院 国内精品 | 天天综合天天做 | 国产美女主播精品一区二区三区 | 欧美一级片在线 | 国产一区91 | 五月婷婷久久综合 | av免费观看网址 | 国产亚洲欧美在线视频 | 97免费视频在线播放 | 久久免费看 | 一区二区国产精品 | 久久99热精品这里久久精品 | 国产福利91精品张津瑜 | 久久激情小视频 | 9色在线视频 | 久久免费av电影 | 最新av网址在线观看 | 久av电影 | 亚洲欧美综合精品久久成人 | 亚洲国产三级在线观看 | 伊人黄色网 | 日韩黄色在线观看 | 午夜av一区二区三区 | 国产在线理论片 | 日韩伦理一区二区三区av在线 | 在线观看视频免费大全 | 中文字幕精品一区二区精品 | 日日夜夜亚洲 | 狠狠插狠狠操 | 在线激情网 | 在线观看免费版高清版 | 久久在线视频在线 | 国产精品视频免费观看 | 干干日日 | 日韩在线视频免费观看 | 美女久久 | 色妞色视频一区二区三区四区 | 成年人免费在线观看网站 | 曰本免费av | 天天操天天摸天天爽 | 一区二区久久久久 | 日批网站免费观看 | 久久婷婷一区 | 97视频亚洲 | 9i看片成人免费看片 | 国产主播大尺度精品福利免费 | 日本午夜在线观看 | 成人黄性视频 | 国产在线v | 伊人超碰在线 | 日本论理电影 | 免费高清在线一区 | 欧美激情亚洲综合 | 亚洲黄色成人网 | 一区二区三区 亚洲 | 婷婷丁香九月 | 射射射综合网 | 色在线最新 | 黄色毛片在线观看 | 久草免费色站 | 欧美大片aaa | 麻豆91视频 | 99精品视频在线观看 | 国产精品久久久久久99 | 五月天婷婷免费视频 | 欧美日韩中文视频 | 99福利片 | 日韩精品一区电影 | 麻豆免费在线播放 | 亚洲精品字幕在线观看 | 欧美激情视频免费看 | 日韩av在线高清 | 色五月成人 | 久久免费视频4 | av不卡中文 | 国产欧美久久久精品影院 | 国产精品视频在线观看 | 日韩黄色免费看 | 91精品老司机久久一区啪 | 国产精品18videosex性欧美 | 国产黄a三级三级 | 91精品啪在线观看国产线免费 | 丁香电影小说免费视频观看 | 日韩精品一区二区三区丰满 | 久久99日韩 | 欧美成人黄 | 国产精品久久久久国产精品日日 | 射久久| 91福利区一区二区三区 | 精品免费一区二区三区 | 中文在线a在线 | 国产五月色婷婷六月丁香视频 | 天天草天天干天天射 | 最新精品国产 | 96av在线视频 | 日韩在线免费播放 | 草久在线播放 | 黄色一级免费 | 超级av在线| 91精品国产麻豆 | 91av99| 夜夜骑日日操 | 欧美一区日韩一区 | 中文字幕在线影院 | 插综合网 | 看片的网址 | av福利第一导航 | 99热手机在线 | 在线视频app | 伊人永久 | 亚洲欧美日韩精品久久奇米一区 | av黄色影院 | av中文在线 | 青青色影院 | 免费高清男女打扑克视频 | 亚洲视频免费在线观看 | 日日综合 | 婷婷丁香在线 | 香蕉视频色 | 日韩在线视频免费播放 | 免费看一及片 | 天天干.com | 久草视频免费播放 | 久久久久综合精品福利啪啪 | 日韩电影一区二区三区 | 麻豆精品视频在线 | 亚洲片在线资源 | 黄色成人影视 | 91精品国产91久久久久久三级 | 国产91免费在线 | 久久成年视频 | 精品国产一二三 | 国产亚洲精品久久久久久大师 | 国产高清区| 二区三区视频 | av中文国产| 日韩av电影中文字幕在线观看 | 国产九九精品视频 | 91大神精品视频在线观看 | 国产高清不卡一区二区三区 | 一级做a视频 | 超级碰碰碰碰 | 视频直播国产精品 | 五月婷婷视频在线 | 欧美aa一级片 | 成年人免费在线观看 | 久久看片 | 久草视频中文在线 | 久草男人天堂 | 久草在线免费新视频 | 国产自在线观看 | 亚洲国内精品在线 | 国产大陆亚洲精品国产 | 视频在线观看99 | 激情av资源 | 日韩在线免费播放 | 中文欧美字幕免费 | 超碰在线成人 | 色视频网页 | 91成人天堂久久成人 | 一性一交视频 | 久久不见久久见免费影院 | 国产精品久久亚洲 | 中文字幕传媒 | 激情婷婷亚洲 | 伊人久久精品久久亚洲一区 | 99久久一区 | 欧美91精品久久久久国产性生爱 | 91精品国自产在线观看欧美 | 99视频播放 | 久青草影院 | 精品免费观看视频 | 国产.精品.日韩.另类.中文.在线.播放 | 成人av影视在线 | 欧美 日韩 国产 中文字幕 | 亚洲国产高清视频 | 美女网站视频久久 | 色99导航 | 精品极品在线 | 九九视频在线 | 色婷婷综合久久久中文字幕 | 久久av中文字幕片 | 高清av中文在线字幕观看1 | 国产一区成人在线 | 91精品国产自产老师啪 | 久久怡红院 | 久亚洲 | 91精品视频在线观看免费 | 五月天伊人 | av在线免费观看网站 | 国产亚洲欧美日韩高清 | 91av片| 久久综合九色欧美综合狠狠 | 国产精品v欧美精品v日韩 | 国产不卡在线观看视频 | 精品视频不卡 | 日韩欧美极品 | 婷婷精品进入 | 精品久久久成人 | av免费在线网 | 国产高清免费在线播放 | 免费观看一级视频 | 国产一区久久久 | 韩国精品视频在线观看 | 婷婷久久网 | 在线电影 你懂得 | 黄污在线看 | 免费在线观看av不卡 | 麻豆免费精品视频 | 99久久精品国产观看 | 91大神电影 | 99福利影院| 亚洲区另类春色综合小说 | 国产成人av网址 | 操碰av | 国产精品原创在线 | 日韩精品中文字幕在线不卡尤物 | 日韩二区在线播放 | 久久99精品国产麻豆婷婷 | 久久夜色精品国产欧美乱 | 久久伊人操 | 91久久奴性调教 | 久久黄色片子 | 日韩精品在线看 | 天天操人 | 黄色一级免费 | 精品亚洲免费 | 夜夜夜夜操 | 久久久99精品免费观看 | 欧美精品久| 日韩欧美在线观看一区二区三区 | 亚洲人人av| 亚洲成人资源在线观看 | 美女久久久久久久久久 | 久久免费精品 | 亚洲丁香日韩 | 久久激情五月激情 | 国产品久精国精产拍 | 狠狠干天天干 | 国内成人av | 成人国产精品电影 | 国产精品免费不 | av免费在线播放 | 国产免费观看久久黄 | 久久99亚洲精品久久久久 | 国产中文字幕在线看 | 日韩欧美一二三 | 91超碰免费在线 | 狠色在线| 97视频免费观看2区 亚洲视屏 | 色视频网站免费观看 | 免费久久久| 成人高清av在线 | 久久综合久久综合九色 | 日韩精品中字 | 国产在线播放一区 | 五月视频 | 91香蕉视频 | 日韩欧美视频免费观看 | 在线播放第一页 | 四虎影视成人 | 999超碰| 香蕉视频在线观看免费 | 99在线高清视频在线播放 | 超碰97免费 | 99精品一区二区 | 国产成人精品一区二区在线观看 | 久香蕉 | 国产成人久久精品77777综合 | 97在线精品 | 四虎永久网站 | 中文在线免费观看 | 国产欧美最新羞羞视频在线观看 | 亚洲视频电影在线 | 免费在线国产黄色 | 日韩欧美一区二区三区视频 | 国产成人精品区 | 综合色播| 成人一区二区三区在线 | 日韩电影久久 | 国产精品免费久久久久 | 国产二区视频在线 | 久久免费在线观看 | 国产人在线成免费视频 | 成人精品影视 | 91c网站色版视频 | 久久久午夜精品福利内容 | 一区二区电影在线观看 | 999视频在线播放 | 天天干天天操天天射 | 国产成人久久 | 在线免费高清一区二区三区 | 国产精品久久久久久久久久久久午夜 | 亚洲国产片 | 国产精品专区在线 | 香蕉视频在线观看免费 | 国产综合精品一区二区三区 | 久久久2o19精品 | 精品国产免费人成在线观看 | 久久久久久国产精品 | 在线免费观看麻豆视频 | av色图天堂网 | 在线免费色 | 午夜久操 | 亚洲精品在线一区二区 | 免费a v在线 | 人人爽人人搞 | 久久精品官网 | 亚洲精品va | 国产精品久久久久久久久久 | 免费亚洲成人 | 欧美日韩免费网站 | 久久人人爽人人爽 | 91热在线| 久久你懂的 | 国产美女免费观看 | 久久国产精品精品国产色婷婷 | 久久福利电影 | 91丨九色丨蝌蚪丰满 | 日韩精品一区二区免费视频 | 色综合久久精品 | 欧美一区中文字幕 | 在线激情网 | 黄色一级动作片 | 国产在线中文 | 蜜桃传媒一区二区 | 日韩电影一区二区三区在线观看 | 免费日韩一区 | 亚洲国产中文字幕在线视频综合 | 久久精品国产亚洲 | 九九热免费在线观看 | 国产成人久久久久 | 91av电影网| 国产成人一区二区精品非洲 | 国产麻豆视频免费观看 | 国产视频一区二区在线 | 亚洲美女免费视频 | 国色天香第二季 | 99亚洲国产精品 | 在线欧美中文字幕 | 国产区av在线 | 国产精品成人自产拍在线观看 | 国内外成人在线视频 | 久草热久草视频 | 亚洲精品短视频 | 国产色视频123区 | 中文字幕免费一区 | 日韩理论电影网 | 丝袜精品视频 | 美女黄濒 | 在线观看网站你懂的 | 久久毛片网 | 日韩v欧美v日本v亚洲v国产v | 日本视频高清 | 免费久久久久久 | 成人免费 在线播放 | 国产精品久久久久久久久免费 | 国产精品麻豆一区二区三区 | 日韩一区二区三区在线看 | 九九热99视频| 99精品亚洲| 免费 在线 中文 日本 | 国语精品免费视频 | 国产亚洲在线 | 五月天网站在线 | 亚洲一级特黄 | 国产一区二区三区高清播放 | 国产精品久久久久久久久久久久 | 成人免费观看在线视频 | 欧美一级免费高清 | 五月天丁香 | 久久午夜电影院 | 亚洲亚洲精品在线观看 | 亚洲一区二区精品3399 | 国产精品美女久久久免费 | 欧美大片aaa | 成年人电影免费在线观看 | 最近日本中文字幕a | 亚洲国产视频网站 | 婷婷丁香狠狠爱 | 欧美网站黄色 | 久久成人18免费网站 | 久久久久亚洲最大xxxx | 狠狠色丁香婷婷综合久小说久 | 久久久国产影院 | 99视频免费 | 亚洲黄网站 | 最近2019好看的中文字幕免费 | 精品一二三区 | 就操操久久 | 国产成人精品午夜在线播放 | 亚洲毛片在线观看. | 亚洲最新视频在线播放 | 黄色中文字幕 | 久久成人国产精品 | 欧美极品久久 | 九九交易行官网 | 亚洲 成人 欧美 | 国产成人777777 | 日本中文不卡 | 视频一区二区在线 | 国产精品久久久久久久久久久杏吧 | 日韩电影一区二区在线 | 亚洲国产精品一区二区尤物区 | 丁香婷婷激情啪啪 | 日韩乱码中文字幕 | 国产成人精品一区二区三区福利 | 久久不卡日韩美女 | 在线免费黄 | 精品久久久久久亚洲综合网 | 国产精品久久久久永久免费观看 | 中文字幕在线观 | 欧美a级成人淫片免费看 |