Java集合框架學習

2022-01-08 小林家的龍
java集合框架java常用集合框架簡單入門

java集合框架是jdk提供的一種容器,用來存儲對象信息

所有集合類都位於java.util包下,支持多線程的集合類位於java.util.concurrent包

java集合框架裡封裝了很多的算法和操作,提供了良好的接口,讓我們的學習十分方便

在下面我們不在稱呼Collection集合,而是稱呼Collection容器

我們操作其中數據也不外乎增刪查改,外加排序(排序暫時先不寫),我們下面就從這幾個角度開始學習

初學集合框架,我們只需要學習Collection和Map及其常用的實現類,

ok,上圖

簡單的看一下,常用的其實也就是這些東西了.

Collection接口及其實現

Collection接口有兩個有兩個子接口,分別是set和list,我們知道,接口代表一種規範,現在來看一下這兩個子接口自己的規範

set:這個接口就可以理解為數學意義上的集合了,  裡面存儲的元素,無序不可重複

list:這個接口可以叫做列表,裡面存儲的元素有序可以重複

先理解到這兒,我們再看看他們具體的實現類

ListArrayList實現類

這個圖就比較詳細了,現在看不懂也沒事,略過

這些都是List的實現類,可以看到有很多,我們只關心現在要學的就行了

這個類的底層採用數組的存儲方式

我們知道數組是在內存裡開闢了一塊連續的內存空間,有索引.所以ArrayList在查找元素的時候可以通過索引訪問,速度很快。但是增刪元素的話(若增刪中間位置的元素),後面的所有元素都要進行一次移位,數據量一旦一大,速度立馬就慢下來了。

特點:ArrayList的底層採用數組的結構,增刪慢查詢快。

排序的話需要傳入一個比較器,我們稍後再說

代碼示例:(這個代碼有很多不規範的地方,比如泛型,這是為了儘量不出現未知的內容才這樣做的往後代碼也是)


這個類還有很多api,想要了解的同學可以通過

https://www.matools.com/api/java8

在線查看學習

源碼分析:

我們從創建空arratlist開始,到添加一個元素,看看它內部是怎麼做的

它內部也是創建了一個空數組,元素的數量size沒有定義,默認是0,但是這個默認的初始容量是10,這個又是什麼呢?這個呀,就是在內存中實際開闢的空間。但是如果我們不添加元素的話是不會生效的,只要我們添加了一個元素,這個arraylist就在內存中開闢10個單位的空間了。

那麼添加的元素如果超出了這個容量怎麼辦?這個就涉及到arraylist的擴容問題了,我們稍後再看

transient的意思是不參加序列化和反序列化,不知道啥意思的就忽略

   private static final int DEFAULT_CAPACITY = 10;   private int size;transient Object[] elementDataprivate static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};public ArrayList() {       this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}

現在我們來添加一個元素,他內部是怎麼幫我們實現的,這些方法的調用關係從上到下我給大家排序好了,接下來跟著我走

1,我們在調用add方法的時候,首先會調用ensureCapacityInternal(size + 1)方法,在這個方法裡又調用了ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

2,calculateCapacity()會判斷現在數組和原來的空數組是否相同,如果是相同的就返回默認容量和現在數組的長度中最大的一個,注意我們現在是第一次添加,也就是我們添加一個元素,數組的容量直接就變成了10。這個函數的作用就是計算添加這個元素所需要的容量

3,ensureExplicitCapacity()會判斷現在的容量夠不夠添加這個元素所需要的容量,如果夠的話就什麼也不做,不夠的話就調用grow()方法進行擴容

4, grow()方法用來對數組進行擴容,仔細看。他是先拿到老數組的長度,然後給老數組長度增加0.5倍變成新數組長度。

下面代碼第二行是二進位移位操作,二進位中向右移位1,在十進位中就是除2。所以增長了0.5倍

       int oldCapacity = elementData.length;       int newCapacity = oldCapacity + (oldCapacity >> 1);

然後判斷新數組長度夠不夠用,如果還是不夠,就將添加這個元素所需的容量設置為新數組的容量

       if (newCapacity - minCapacity < 0)           newCapacity = minCapacity;

接下來沒有什可看的了,因為接下來是判斷這個長度有沒有長處數組的最大長度,超出了就報錯,現在這麼理解就行了,想看具體細節就去看源碼。

如果長度合法的話就通過Arrays.copyOf()方法,為數組設置新的容量

       if (newCapacity - MAX_ARRAY_SIZE > 0)           newCapacity = hugeCapacity(minCapacity);              elementData = Arrays.copyOf(elementData, newCapacity);

原始碼貼上:

public boolean add(E e) {       ensureCapacityInternal(size + 1);         elementData[size++] = e;       return true;  }
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }

private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { modCount++;
if (minCapacity - elementData.length > 0) grow(minCapacity); }
private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }

這個添加的方法,其他的操作也可以通過這個思路去理解源碼。此處的性能優化就只有避免或減少擴容操作


LinkedList實現類

前置,再了解LinkedList之前先說先什麼是鍊表,鍊表是一種數據結構,就跟鏈條一樣,有一個個的節點。鍊表在內存中並不是一組連續的內存空間,而是散亂的,通過指針將這些散亂的數據連接起來。鍊表有頭節點和尾節點,除過尾節點,剩下每個節點都有一個指針指向下一個節點,這樣就像數據串聯了起來,像一條鏈子一樣。每個內存單元都存有數據和一個指針。

下圖這個就是典型的一個單向鍊表,


如果每個內存單元有兩個指針分別指向上一個元素和下一個元素,最兩端的節點即使頭也是尾,這個就是雙向鍊表。

如果將單鍊表的尾節點的指針指向頭,形成一個環形,這個就是循環鍊表。這倆都是鍊表的不同形式。

我們很多的數據結構都是基於鍊表來的,比如棧,隊列等


關係圖:

雙鍊表實現了List和Deque接口。實現所有可選列表操作,並允許所有元素(包括null )。

所有的操作都能像雙向列表一樣預期。索引到列表中的操作將從開始或結束遍歷列表,以更接近指定的索引為準。

請注意,此實現不同步。 如果多個線程同時訪問連結列表,並且至少有一個線程在結構上修改列表,則必須在外部進行同步。(結構修改是添加或刪除一個或多個元素的任何操作;僅設置元素的值不是結構修改。)這通常通過在自然封裝列表的對象上進行同步來實現。如果沒有這樣的對象存在,列表應該使用Collections.synchronizedList方法「包裝」。這最好在創建時完成,以防止意外的不同步訪問列表:

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

這個類的iterator和listIterator方法返回的迭代器是故障快速的 :如果列表在迭代器創建之後的任何時間被結構化地修改,除了通過迭代器自己的remove或add方法之外,迭代器將會拋出一個ConcurrentModificationException 。因此,面對並發修改,迭代器將快速而乾淨地失敗,而不是在未來未確定的時間冒著任意的非確定性行為。

LinkedList 繼承了 AbstractSequentialList 類。

LinkedList 實現了 Queue 接口,可作為隊列使用。

LinkedList 實現了 List 接口,可進行列表的相關操作。

LinkedList 實現了 Deque 接口,可作為隊列使用。

LinkedList 實現了 Cloneable 接口,可實現克隆。

LinkedList 實現了 java.io.Serializable 接口,即可支持序列化,能通過序列化去傳輸

怎麼樣,這個很牛逼吧,但是不怎麼常用,剛開始咱知道就好了

LinekList的Api有多有豐富,基本上常用的需求都能滿足,有很多api功能是一樣地 ,但是名字卻體現了不同數組結構的特性,底層的封裝也略有不同,所以你能應用的方法就是有這些:



想要了解的同學可以通過:

https://www.matools.com/api/java8

在線查看學習,機翻過來的中文不太準確,如果英文好,就去看原版吧,我是個英語渣

 我們看到上述方法的參數大概就可以知道了,這個LinkedList對首尾的操作很豐富,也能用索引進行操作。

特點:

因為鍊表的增刪只是改變了指針的指向而已,更改或增刪一個元素一般只更改一兩個指針,不想ArrayList那樣牽一髮而動全身。所以鍊表的增刪性能高

如果查詢LinkedList的話,就不能像array那樣通過索引直接拿到了,LinkedList的查找是通過指針下移實現的,也就是說,每次都下移指針,然後判斷當前元素。所以鍊表查改效率比array低下

總結:與 ArrayList 相比,LinkedList 的增加和刪除的操作效率更高,而查找和修改的操作效率較低。

源碼分析:

簡單看一下源碼啊,了解了解,有兩個成員變量分別是頭節電和尾節點(transient的意思是不參加序列化和反序列化,不知道啥意思的就忽略),還有一個當前鍊表長度(在這個地方就沒有什麼Capacity的概念了,注意哈)

  transient int size = 0;
transient Node<E> first;
transient Node<E> last;
public LinkedList() { }

為什麼前面說:「所有的操作都能像雙向列表一樣預期。」呢(引自java文檔)看下面這段代碼,這是LinkedList的一個靜態內部類

item表示當前的元素,(E是泛型的意思,不懂的略過,後面說)

next和prev的類型也是Node(節點),這就是當前節點對上下節點的引用。所以這是一個雙向鍊表

 private static class Node<E> {       E item;       Node<E> next;       Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }

創建了LinkedList之後,肯定就是要添加元素了,源碼很多我們只分析add()方法,其他操作方法同理進行分析就行

當我們添加元素的時候,會默認添加到尾部。

    public boolean add(E e) {        linkLast(e);        return true;    }

添加到尾部的具體實現:手寫過鍊表的很這就很簡單了,沒寫過沒事,我後面會寫

拿到當前鍊表的最後一個元素 l

創建一個新的節點,新節點的上一個元素引用 l,並將當前值存入,然後讓下一個節點的引用尾null,也就是說現在我們添加的節點就是尾節點了

判斷添加前的最後一個節點是不是空,如果是空的話那麼這個鍊表就只有一個元素,當前節點即是頭節點也是尾節點

若添加前的最後一個節點是不是空,那麼添加前的最後一個節點的下一個節點就引用當前節點

長度加一,modCount++不用管,這個是用來記錄改變次數的。

我說的不清楚,但是邏輯確實很簡單,仔細看一下源碼

     void linkLast(E e) {        final Node<E> l = last;        final Node<E> newNode = new Node<>(l, e, null);        last = newNode;        if (l == null)            first = newNode;        else            l.next = newNode;        size++;        modCount++;    }

addFirst():這個是添加元素到第一個邏輯也很簡單

  public void addFirst(E e) {        linkFirst(e);    }
private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }

比較複雜的add()是添加到指定的索引位置

   public void add(int index, E element) {       checkPositionIndex(index);
if (index == size) linkLast(element); else linkBefore(element, node(index)); }
private void checkPositionIndex(int index) { if (!isPositionIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
private boolean isPositionIndex(int index) { return index >= 0 && index <= size; }
void linkBefore(E e, Node<E> succ) { final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
Node<E> node(int index) {
if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }

看著挺多的,現在進行分解:

 public void add(int index, E element) {       checkPositionIndex(index);
if (index == size) linkLast(element); else linkBefore(element, node(index)); }

首先會調用checkPositionIndex(index)檢查角標是否合法

private void checkPositionIndex(int index) {       if (!isPositionIndex(index))           throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  }   private boolean isPositionIndex(int index) {       return index >= 0 && index <= size;  }
if (index == size) linkLast(element);

若不符合上述情況,就執行linkBefore(element, node(index));

先看node()

void linkBefore(E e, Node<E> succ) {              final Node<E> pred = succ.prev;       final Node<E> newNode = new Node<>(pred, e, succ);       succ.prev = newNode;       if (pred == null)           first = newNode;       else           pred.next = newNode;       size++;       modCount++;  }              Node<E> node(int index) {                     if (index < (size >> 1)) {           Node<E> x = first;           for (int i = 0; i < index; i++)               x = x.next;           return x;      } else {           Node<E> x = last;           for (int i = size - 1; i > index; i--)               x = x.prev;           return x;      }  }

好了,就這樣。我們就完成了在鍊表中間插入元素了。breeze!

關於LinkedList的其他玩法,喜歡就自己再找找,如果實在不會,那就跟著教程手寫一個鍊表,就啥都清楚了。

Set

set容器的話呢,就是數學意義上的集合,元素無序不重複,而且不能通過索引來訪問元素,只能通過元素本身來訪問自己

HashSet實現類

HashSet的底層是什麼呢,就是HashMap。為什麼呢,因為HashSet就是HashMap的key,而HashMap的值都指向同一個地方罷了,現在聽不懂這句話沒有關係。就先略過。

api:HashSet的api很少

booleanadd(E e)
將指定的元素添加到此集合(如果尚未存在)。
voidclear()
從此集合中刪除所有元素。
Objectclone()
返回此 HashSet實例的淺層副本:元素本身不被克隆。
booleancontains(Object o)
如果此集合包含指定的元素,則返回 true 。
booleanisEmpty()
如果此集合不包含元素,則返回 true 。
Iterator<E>iterator()
返回此集合中元素的迭代器。
booleanremove(Object o)
如果存在,則從該集合中刪除指定的元素。
intsize()
返回此集合中的元素數(其基數)。
Spliterator<E>spliterator()
在此集合中的元素上創建late-binding和故障快速 Spliterator 。

源碼分析:

首先創建對象,我們來看看無參的構造器

發現底層還是創建了HashMap()

PRESENT成員變量就是HashSet底層的HashMap的值的引用對象,所有的值都引用這一個對象

而且源碼有說到,這個HashMap的初始容量是16,負載因子是0.75.

初始容量我們已經理解,但是負載因子是啥呢,我們後面再說

  private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public HashSet() { map = new HashMap<>(); }

接下來我們該到添加元素了,看一下add()的實現:還是調用了HashMap的添加元素的put方法。

public boolean add(E e) {       return map.put(e, PRESENT)==null;}

Map接口及其實現

Map與List、Set接口不同,它是由一系列鍵值對組成的集合,提供了key到Value的映射。同時它也沒有繼承Collection。在Map中它保證了key與value之間的一一對應關係。也就是說一個key對應一個value,所以它不能存在相同的key值,當然value值可以相同。

這個key就像函數中的x,value就像函數中的y。

多個y可以對應一個x,一個x只能對應一個y

HashMap實現類

api:那個keySet()方法的返回值就是一個Set。這下就明白了,HashSet和HashMap的關係了

這些api就不做演示了,沒啥意思

在看源碼之前,先了解一下Hash(哈希)

什麼是 Hash

Hash(哈希),又稱「散列」。

散列(hash)英文原意是「混雜」、「拼湊」、「重新表述」的意思。

在某種程度上,散列是與排序相反的一種操作,排序是將集合中的元素按照某種方式比如字典順序排列在一起,而散列通過計算哈希值,打破元素之間原有的關係,使集合中的元素按照散列函數的分類進行排列。

在介紹一些集合時,我們總強調需要重寫某個類的 equlas() 方法和 hashCode() 方法,確保唯一性。這裡的 hashCode() 表示的是對當前對象的唯一標示(一般是地址)。計算 hashCode 的過程就稱作 哈希。

為什麼要有 Hash

我們通常使用數組或者鍊表來存儲元素,一旦存儲的內容數量特別多,需要佔用很大的空間,而且在查找某個元素是否存在的過程中,數組和鍊表都需要挨個循環比較,而通過 哈希 計算,可以大大減少比較次數。

Hash衝突

如果兩個數據算出了一個哈希值,就叫做Hash衝突,也叫Hash碰撞

負載因子



我們不深入研究Hash函數怎麼寫,現在知道這些就暫時夠用了,記住一下特點:

同一個value只會算出一個hash值。

不同的value可能會算出同一個hash值。

一個value絕對不可能算出不同的hash值



原理:


HashMap的實現原理

HashMap的主幹是一個Entry數組。Entry是HashMap的基本組成單元,每一個Entry包含一個key-value鍵值對。(其實所謂Map其實就是保存了兩個對象之間的映射關係的一種集合)HashMap由數組+鍊表組成的,數組是HashMap的主體,鍊表則是主要為了解決哈希衝突而存在的,如果定位到的數組位置不含鍊表(當前entry的next指向null),那麼查找,添加等操作很快,僅需一次尋址即可;如果定位到的數組包含鍊表,對於添加操作,首先遍歷鍊表,存在即覆蓋,否則新增;對於查找操作來講,仍需遍歷鍊表,然後通過key對象的equals方法逐一比對查找。所以,性能考慮,HashMap中的鍊表出現越少,性能才會越好調整HashMap的參數使其更適合相應場景,這便是調優。

簡單源碼分析:

      public HashMap() {       this.loadFactor = DEFAULT_LOAD_FACTOR;   }


public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else 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); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }

好了,HashMap了解到這裡就ok,但是HashMap的存取順序可不一樣,如果我們要保證存取順序一致的話,就使用LinkedHashMap就行了,至於HashTable的話,官方都不建議使用了,我也就不看了

泛型

泛型的使用很簡單,就不看源碼了

泛型類
public class MyGeneric<T>{   T t;  public void show(T t){   sout(t);}  public T getT(){   return t;}}

public class TestGeneric{ public static void main(String[] args){            MyGeneric<String> myGeneric = new MyGeneric<String>();   myGeneric.t = "hello";   myGeneric.show("hello world!");   String string = myGeneric.getT();      MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();   myGeneric2.t = 100;   myGeneric2.show(200);   Integer integer = myGeneric2.getT();   }}


泛型接口


語法:接口名

COPYpublic interface MyInterface<T> {   String nameString="tang";   T server(T t);}COPYpublic class MyInterfaceImpl implements MyInterface<String>{@Overridepublic String server(String t) {System.out.println(t);return t;}}COPYMyInterfaceImpl myInterfaceImpl=new MyInterfaceImpl();myInterfaceImpl.server("xxx");COPYpublic class MyInterfaceImpl2<T> implements MyInterface<T>{@Overridepublic T server(T t) {System.out.println(t);return t;}}COPYMyInterfaceImpl2<Integer> myInterfaceImpl2=new MyInterfaceImpl2<Integer>();myInterfaceImpl2.server(2000);

注意:不能泛型靜態常量

泛型方法

語法:返回值類型

public class MyGenericMethod{  public <T> T show(T t){   sout("泛型方法" + t);   return t;}}
MyGenericMethod myGenericMethod = new MyGenericMethod();myGenericMethod.show("字符串");myGenericMethod.show(200);myGenericMethod.show(3.14);

泛型集合

概念:參數化類型、類型安全的集合,強制集合元素的類型必須一致

 public static void main(String[] args) {       HashMap<Integer,String> map = new HashMap();       map.put(1,"Str1");  }

特點:

編譯時即可檢查,而非運行時拋出異常

訪問時,不必類型轉換(拆箱)

不同泛型之間應用不能相互賦值,泛型不存在多態

迭代器和工具類

Java Iterator(迭代器)不是一個集合,它是一種用於訪問集合的方法,可用於迭代 ArrayList 和 HashSet 等集合


import java.util.ArrayList;import java.util.Iterator;public class QianniuTest {public static void main(String[] args) {
ArrayList<String> sites = new ArrayList<String>(); sites.add("qianniu1"); sites.add("qianniu2"); sites.add("qianniu3"); sites.add("qianniu4");
Iterator<String> it = sites.iterator();
while(it.hasNext()) { System.out.println(it.next()); }}


迭代器 it 的兩個基本操作是 next 、hasNext 和 remove。

調用 it.next() 會返回迭代器的下一個元素,並且更新迭代器的狀態。

調用 it.hasNext() 用於檢測集合中是否還有元素。

調用 it.remove() 將迭代器返回的元素刪除。

另外還有兩個工具類Arrays和Collections

這兩個工具類分別用來操作數組和集合,提供了一些常用的其他功能。十分的簡單。

另外還有TreeSet和TreeMap之類的集合沒有記,因為這些涉及到了紅黑樹,函數式接口等知識。

另外關於迭代器遍歷和普通for遍歷的區別:迭代器只能遍歷一次,而且不能更改集合中的值,因為迭代器用的指針。但是for你就可以隨便整了

那為什麼要用迭代器呢,當然是因為性能,10000個1的集合。迭代器比for差不多能快三倍。forEach的底層就是迭代器。

額,應該沒啥了,常用的也差不多了。


如有錯誤,懇請指正。

如能相助,萬分榮幸。



相關焦點

  • 程式設計師編程知識總結之Java 集合框架
    集合框架被設計成要滿足以下幾個目標。為此,整個集合框架就圍繞一組標準接口而設計。你可以直接使用這些接口的標準實現,諸如:LinkedList, HashSet, 和 TreeSet等,除此之外你也可以通過這些接口實現自己的集合。集合框架是一個用來代表和操縱集合的統一架構。所有的集合框架都包含如下內容:接口:是代表集合的抽象數據類型。
  • Java集合類框架
    作者丨Henry扶蘇來源丨Henry扶蘇簡介        在平時的開發裡我們經常用到集合框架
  • JAVA 集合框架之List接口之ArrayList
    以下是小猿畫的一個集合框架圖,僅供參考。首先,給大家講解一下什麼是集合框架。集合可以看作是一種容器,用來存儲對象信息。所有的集合類都位於 java.util 包下,主要是由兩大接口派生出來的:Collection 和 Map。但是,支持多線程的集合類位於 java.util.concurrent 包下。
  • Java集合乾貨系列-集合總體大綱
    java提供的工具包,包含了常用的數據結構:集合、鍊表、隊列、棧、數組、映射等。Java集合工具包位置是java.util.*Java集合主要可以劃分為4個部分:List列表、Set集合、Map映射、工具類(Iterator迭代器、Enumeration枚舉類、Arrays和Collections)。Java集合工具包框架圖(如下):
  • Java 集合框架看這一篇就夠了
    學習這些集合框架,我認為有 4 個目標:對不同的場景,能夠選擇合適的數據結構並分析優缺點;關於 Map,之前那篇 HashMap 的文章已經講的非常透徹詳盡了,所以本文不再贅述。操作集合,無非就是「增刪改查」四大類,也叫 CRUD:Create, Read, Update, and Delete.
  • Java後端學習流程
    首先,我個人比較推崇的學習方法是:先學java前端,也就是HTML,css,js,因為學習java以後肯定是往java ee方向發展的,學習完前端
  • 【精選乾貨】Java集合框架完全解析
    Java集合框架為我們提供了一組基本機制以及這些機制的參考實現,其中基本的集合接口是Collection接口,其他相關的接口還有Iterator接口、RandomAccess接口等。這些集合框架中的接口定義了一個集合類型應該實現的基本機制,Java類庫為我們提供了一些具體集合類型的參考實現,根據對數據組織及使用的不同需求,只需要實現不同的接口即可。
  • 50道Java集合經典面試題(收藏版)
    Collection是Java集合框架中的基本接口,如List接口也是繼承於它public interface List<E> extends Collection<E> {Collections是Java集合框架提供的一個工具類,其中包含了大量用於操作或返回集合的靜態方法。
  • 幾種Java常用序列化框架的選型與對比
    public static MessageInfo buildMessage() { MessageInfo messageInfo = new MessageInfo(); messageInfo.setUsername("abcdefg"); messageInfo.setPassword("123456789"); messageInfo.setAge
  • java集合面試攻略
    本文嘗試從底層剖析主流集合的底層結構與實現原理,如無特殊說明,本文源碼出自jdk1.8。java集合架構圖,來源於網絡java集合的2個頂級接口Collection和Map。話不多說,接下來我們對它們作一一介紹。先對java.util.Map的4個常用實現類做簡單的介紹及對比。
  • 40道Java集合面試題和答案
    Java集合框架為Java程式語言的基礎,也是Java面試中很重要的一個知識點。
  • Java【IO系列】基礎篇—1. IO框架
    關於java的io部分,以前學習過。
  • 2016年7款最佳 Java 框架
    不管文檔有多少,Spring MVC都可能並非是一個Java開發的新手能掌控的,儘管這並不是框架的一個直接缺陷,但學習曲線真的是有點太陡了。因此,在碰到這個 Java 框架中文檔相對比較缺乏的某些部分時,處理起來是會有點困難的。你找的信息如果版本不同,興許也會有差異。順便提一句,依據我們的工程師的至上經驗,Spring MVC是我們最喜愛的框架之一。2.
  • java 基礎 之 集合 Map
    //: containers/Maps.java// Things you can do with Maps.import java.util.concurrent.*;import java.util.*;import net.mindview.util.
  • Java高頻面試之:集合類
    集合類不安全問題Java中的集合類,我們都知道是面試中登場率最高的了,不給你刨根問底地深究一下各種集合類的底層原理,好像就凸顯不出面試官的厲害(所以面試到底是給誰裝X用的?)。校驗的原理也很簡單,就是對比當前的集合的修改次數與當時Itr對象創建時記錄的次數,如果不一致,就是被修改過了。
  • Java Set集合的詳解
    2、☞ 《Java面試手冊》.PDF    點擊查看1、SetSet:注重獨一無二的性質,該體系集合可以知道某物是否已經存在於集合中,不會存儲重複的元素。用於存儲無序(存入和取出的順序不一定相同)元素,值不能重複。
  • java三大框架介紹
    常聽人提起三大框架,關於三大框架,做了如下了解: 三大框架:Struts+Hibernate+Spring java
  • 死磕 java所有集合之終結篇
    點擊下面連結可以直接到相應的章節查看:死磕 java集合之HashMap源碼分析死磕 java集合之LinkedHashMap源碼分析死磕 java集合之WeakHashMap源碼分析死磕 java集合之TreeMap源碼分析(一)死磕 java集合之TreeMap源碼分析(二)死磕 java集合之TreeMap
  • 最熱門的13個Java微服務框架
    該框架享有多年Java開發中建立的所有深度連接,包括所有主要和次要數據存儲、LDAP伺服器和Apache Kafka等消息傳遞工具的集成。還有許多用於維護運行伺服器集合的小特性,比如Spring Vault,這是一種用於維護生產環境中伺服器所需的密碼的工具。所有這些優點都說明了為什麼Java程式設計師多年來一直喜歡Spring Boot的原因。
  • 13個最熱開源微服務 Java 框架
    該框架享有多年 Java 開發所構建的深層連接,包括所有主要和次要數據存儲,LDAP 伺服器以及 Apache Kafka 等消息傳遞工具集成,眾多維護運行伺服器集合的小功能,比如 Spring Vault,維護生產伺服器所需密碼等。