Java集合類簡介

基本概念

Java的集合類,也可以叫做容器類,用來“保存對象”。它有兩種:

Collection

如果保存的對象是單個對象,就是 Collection 類。Collection 類就是一個接口。先看看它的實現類和子接口。
Collection Interface
這裏面最重要的子接口是:Set, List, Queue. JDK 文檔說了,JDK不提供Collection接口的直接實現。
看到這裏挺納悶的,明明有那麼多類實現了Collection接口,這不是亂說嗎?難道是老的JDK有沒有直接實現,新的JDK已經有直接實現了,帶着問題小心求證一下:

JDK7: https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html
The JDK does not provide any direct implementations of this interface: it provides implementations of more specific subinterfaces like Set and List. 

JDK8: https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html
The JDK does not provide any direct implementations of this interface: it provides implementations of more specific subinterfaces like Set and List. 

JDK9: https://docs.oracle.com/javase/9/docs/api/java/util/Collection.html
The JDK does not provide any direct implementations of this interface: it provides implementations of more specific subinterfaces like Set and List.

JDK10: https://docs.oracle.com/javase/10/docs/api/java/util/Collection.html
The JDK does not provide any direct implementations of this interface: it provides implementations of more specific subinterfaces like Set and List. 

事實結果說明我的假設是錯的。

Class name type related jar description
ValuesView in ConcurrentHashMap (java.util.concurrent) inner class JDK rt.jar 沒有實現add 和 addAll 方法
BeanContext (java.beans.beancontext) interface JDK rt.jar public interface BeanContext extends BeanContextChild, Collection, DesignMode, Visibility
Multiset (com.google.common.collect) interface guava-27.0.1-jre.jar 一個像Set一樣可以保存元素的集合,不過它可以保存重複的元素,這種集合又稱之爲Bag
CheckedCollection in Collections (java.util) inner class JDK rt.jar 一個代理類,在創建的時候傳入被代理的Collection對象
Set (java.util) interface JDK rt.jar 不包含重複元素的集合。 更正式的是,集不包含一對元素 e1 和 e2,使得 e1.equal(e2),最多包含一個null元素。 顧名思義,此接口對數學集抽象進行模型。
SynchronizedCollection in Synchronized (com.google.common.collect) inner class guava-27.0.1.jar static class SynchronizedCollection extends SynchronizedObject implements Collection 通過 synchronized (mutex) {}的方式給代理對象加鎖
SynchronizedCollection in Collections (java.util) inner class rt.jar static class SynchronizedCollection implements Collection, Serializable 通過 synchronized (mutex) {}的方式給代理對象加鎖
ContextStack in ThreadContext (org.apache.logging.log4j) inner interface log4j-api.2.11.2.jar The ThreadContext Stack interface.
AbstractCollection (java.util) abstract class JDK rt.jar 沒有實現add(E var1)等方法,會拋UnsupportedOperationException
List (java.util) interface rt,jar 有序集合(也稱爲序列)。該界面的用戶可以精確控制列表中每個元素的插入位置。用戶可以通過其整數索引(列表中的位置)訪問元素,並在列表中搜索元素。
CollectionView in ConcurrentHashMap (java.util.concurrent) inner abstract static class JDK rt.jar 沒有實現完Collection接口的方法。
ForwardingCollection (com.google.common.collect) abstract class abstract class 裝飾器模式,允許用戶向現有對象添加新功能,而無需更改其結構。這種設計模式屬於結構模式,因爲該模式充當現有類的包裝。
UnmodifiableCollection in Collections (java.util) innner static class rt.jar 包含一個final屬性final Collection<? extends E> c;
Queue (java.util) interface rt.jar 設計用於在處理之前容納元素的集合。除了基本Collection操作外,隊列還提供其他插入,提取和檢查操作。這些方法中的每一種都以兩種形式存在:一種在操作失敗時引發異常,另一種返回一個特殊值(null或false,取決於操作)。插入操作的後一種形式是專門爲限制容量的Queue 實現而設計的。在大多數實現中,插入操作不會失敗。

可以看出,Collection 接口最重要的子接口就是List, Set 和 Queue 了。

先看看Collection的所有方法:
Collection methods

List

List interface
有序集合(也稱爲序列)。該界面的用戶可以精確控制列表中每個元素的插入位置。用戶可以通過其整數索引(列表中的位置)訪問元素,並在列表中搜索元素。
和 Set 相比:

  • List 允許重複的元素, 也就是說,e1.equals(e2), 可以插入e1 和 e2.
  • List 如果完全允許使用空元素,則通常允許使用多個空元素。允許插入多個 null 元素.
    List 相較於 Collection 接口,擴展了根據索引位置操作元素的方法:
  • get(int)
  • set(int, E)
  • add(int, E)
  • remove(int)

List 還提供了根據給的對象找索引的方法。

  • indexOf(Object). 查到第一次出現給定對象的索引位置。
  • lastIndexOf(Object) , 查找List當中最後一次出現給定對象的位置。

還有返回ListIterator的方法:

  • listIterator() 返回此列表中的元素的列表迭代器(按適當順序) ListIterator。
  • listIterator(int) 從列表中的指定位置開始,以適當的順序返回在此列表中的元素上的列表迭代器 ListIterator。
    插一句嘴,Iterator 和 Iterable 的區別:
package java.util;

import java.util.function.Consumer;

public interface Iterator<E> {
    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    default void forEachRemaining(Consumer<? super E> var1) {
        Objects.requireNonNull(var1);

        while(this.hasNext()) {
            var1.accept(this.next());
        }

    }
}
package java.lang;

import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;

public interface Iterable<T> {
    Iterator<T> iterator();

    default void forEach(Consumer<? super T> var1) {
        Objects.requireNonNull(var1);
        Iterator var2 = this.iterator();

        while(var2.hasNext()) {
            Object var3 = var2.next();
            var1.accept(var3);
        }

    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(this.iterator(), 0);
    }
}

Iterator 有方法:

  • hasNext() 如果迭代具有更多元素,則返回true。
  • next() 返回迭代中的下一個元素。
  • remove() 從基礎集合中移除此迭代器返回的最後一個元素(可選操作)。
  • forEachRemaining​(Consumer<? super E> action) 對剩餘的每個元素執行給定的操作,直到所有元素都已處理或該操作引發異常。
    Iterable 有方法:
  • default void forEach​(Consumer<? super T> action) 對中的每個元素執行給定的操作,Iterable 直到所有元素都已處理或該操作引發異常。
  • Iterator iterator​() 返回類型爲的元素上的迭代器T。
  • default Spliterator spliterator​() Spliterator在this所描述的元素上 創建一個Iterable。

從java9開始,List 還提供一堆of方法,就是返回一個大小不可變的List. 代碼實現是用了ImmutableCollections類的方法。
比如返回有N個原屬構成的大小固定的List
看到沒有,爲了達到大小不可變,本質上就是用final修飾了: private final E[] elements;

    static final class ListN<E> extends AbstractImmutableList<E>
            implements Serializable {

        // EMPTY_LIST may be initialized from the CDS archive.
        static @Stable List<?> EMPTY_LIST;

        static {
            VM.initializeFromArchive(ListN.class);
            if (EMPTY_LIST == null) {
                EMPTY_LIST = new ListN<>();
            }
        }

        @Stable
        private final E[] elements;

        @SafeVarargs
        ListN(E... input) {
            // copy and check manually to avoid TOCTOU
            @SuppressWarnings("unchecked")
            E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
            for (int i = 0; i < input.length; i++) {
                tmp[i] = Objects.requireNonNull(input[i]);
            }
            elements = tmp;
        }

        @Override
        public boolean isEmpty() {
            return elements.length == 0;
        }

        @Override
        public int size() {
            return elements.length;
        }

        @Override
        public E get(int index) {
            return elements[index];
        }

        @java.io.Serial
        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            throw new InvalidObjectException("not serial proxy");
        }

        @java.io.Serial
        private Object writeReplace() {
            return new CollSer(CollSer.IMM_LIST, elements);
        }

        @Override
        public Object[] toArray() {
            return Arrays.copyOf(elements, elements.length);
        }

        @Override
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            int size = elements.length;
            if (a.length < size) {
                // Make a new array of a's runtime type, but my contents:
                return (T[]) Arrays.copyOf(elements, size, a.getClass());
            }
            System.arraycopy(elements, 0, a, 0, size);
            if (a.length > size) {
                a[size] = null; // null-terminate
            }
            return a;
        }
    }

關於Stable註解的解釋

如果字段的所有組件變量最多更改一次值,則字段可能被批號爲穩定字段。字段的值計爲其組件值。如果將字段鍵入爲數組,則數組的所有非空組件(深度到字段的數組類型排名)也計爲組件值。通過擴展,任何已批過爲穩定的變量(數組或字段)稱爲穩定變量,其非空值或非零值稱爲穩定值。由於所有字段的引用默認值爲 null(對基元爲零),因此此註釋指示存儲在字段中的第一個非空值(resp.,非零)值永遠不會更改。如果字段不是數組類型,則沒有數組元素,則指示爲穩定的值只是字段的值。如果字段值的動態類型是數組,但靜態類型不是,則數組的組件不是被視爲穩定。如果字段是數組類型,則字段值和字段值的所有組件(如果字段值爲非空)都指示爲穩定。如果字段類型是排名 [@code N = 1] 的數組類型,則字段值的每個組件(如果字段值是非 null)被視爲排名 [@code N-1] 的穩定數組。聲明 [@code 最終] 的字段也可以被條號爲穩定字段。由於最終字段已作爲穩定值,因此此類註釋不會傳達有關字段值更改的其他信息,但如果字段的類型是數組類型()如上所述)。HotSpot VM 依賴於此註釋將非空(resp.,非零)組件值提升爲常量,從而根據此類值(如常量摺疊)實現代碼的卓越優化。更具體地說,HotSpot VM 將以與靜態最終字段類似的方式處理非空穩定字段(最終或其他),從而將字段的值提升爲常量。 因此,撇開空/非空值和數組的差異不談,最終的穩定字段將被視爲 Java 語言和 HotSpot VM 的最終字段。如果爲被批示爲穩定的字段提供第三個值(通過顯式更新穩定字段、穩定數組的組件或通過反射或其他方式更新最終穩定字段),則會發生什麼情況(當前)未定義。由於 HotSpot VM 將非空組件值提升爲常量,因此,如果此類常量(字段的第二個值)用作字段的值(更改爲第三個值),則 Java 內存模型可能會顯示爲損壞).@implNote此註釋僅適用於引導加載程序加載的類的字段。 將忽略在引導加載程序之外加載的類字段上的註釋。

發佈了76 篇原創文章 · 獲贊 9 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章