[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

一、Java集合是什麼?

Java集合實際上是一種經常被運用到的Java類庫,其中提供了已經實現的的數據結構,省去了程序員再次編寫數據結構的事情。在Leetcode中經常會被用到,有很重要的作用。

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中


集合體系

我們發現,無論是Set和List都是繼承於Collection接口,實現Collection之中的方法,而他們又衍生出了HashSet,LinkedList等等我們經常使用的數據結構。

但是真相併不是如此的簡單。

對於Collection接口的實現,其實是由AbstractCollection類完成的。

此類提供了 Collection 接口的骨幹實現,從而最大限度地減少了實現此接口所需的工作。

Collection中需要實現的的方法:

<code> boolean add(E o) 確保此 collection 包含指定的元素(可選操作)。 
 boolean addAll(Collection extends E> c) 
          將指定 collection 中的所有元素都添加到此 collection 中(可選操作)。 
 void clear() 
          移除此 collection 中的所有元素(可選操作)。 
 boolean contains(Object o) 
          如果此 collection 包含指定的元素,則返回 true。 
 boolean containsAll(Collection> c) 
          如果此 collection 包含指定 collection 中的所有元素,則返回 true。 
 boolean equals(Object o) 
          比較此 collection 與指定對象是否相等。 
 int hashCode() 
          返回此 collection 的哈希碼值。 
 boolean isEmpty() 
          如果此 collection 不包含元素,則返回 true。 
 Iterator iterator() 
          返回在此 collection 的元素上進行迭代的迭代器。 
 boolean remove(Object o) 
          從此 collection 中移除指定元素的單個實例,如果存在的話(可選操作)。 
 boolean removeAll(Collection> c) 
          移除此 collection 中那些也包含在指定 collection 中的所有元素(可選操作)。 
 boolean retainAll(Collection> c) 
          僅保留此 collection 中那些也包含在指定 collection 的元素(可選操作)。 
 int size() 
          返回此 collection 中的元素數。 
 Object[] toArray() 
          返回包含此 collection 中所有元素的數組。 
 T[] toArray(T[] a) 
          返回包含此 collection 中所有元素的數組;返回數組的運行時類型與指定數組的運行時類型相同。 /<code> 

AbstractCollection類實現的方法:

<code>
 boolean add(E o) 
          確保此 collection 包含指定的元素(可選操作)。 
 boolean addAll(Collection extends E> c) 
          將指定 collection 中的所有元素添加到此 collection 中(可選操作)。 
 void clear() 
          從此 collection 中移除所有元素(可選操作)。 
 boolean contains(Object o) 
          如果此 collection 包含指定的元素,則返回 true。 
 boolean containsAll(Collection> c) 
          如果此 collection 包含指定 collection 中的所有元素,則返回 true。 
 boolean isEmpty() 
          如果此 collection 不包含元素,則返回 true。 
abstract  Iterator iterator() 
          返回在此 collection 中的元素上進行迭代的迭代器。 
 boolean remove(Object o) 
          從此 collection 中移除指定元素的單個實例(如果存在)(可選操作)。 
 boolean removeAll(Collection> c) 
          從此 collection 中移除包含在指定 collection 中的所有元素(可選操作)。 
 boolean retainAll(Collection> c) 
          僅在此 collection 中保留指定 collection 中所包含的元素(可選操作)。 
abstract  int size() 
          返回此 collection 中的元素數。 
 Object[] toArray() 
          返回包含此 collection 中所有元素的數組。 
 T[] toArray(T[] a) 
          返回包含此 collection 中所有元素的數組;返回數組的運行時類型是指定數組的類型。 
 String toString() 
          返 /<code>

出了一個hashcode方法,AbstractCollection類實現了幾乎所有的功能.

而AbstractCollection類又有三個不同的子類AbstractList,AbstractQueue,AbstractSet。我們從名字就可以知道,這就是三種不同的數據結構。於是這樣基本就可以分析出來。

集合類的構建框架如下:

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

所有的集合都是依靠這種方式構建的,用一個抽象類實現接口,然後再用集合類去實現這些抽象類,來完成構建集合的目的。

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

這是完整的構建圖。

這其實是為了大家有一個思想,就是在Collection實現的方法,在繼承實現他的各個集合中也都會實現。

如下是本文的目錄:

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

二、Iterator接口——迭代器

<code>{
    Boolean hasNext()  如果仍有元素可以迭代,則返回 true。 
     E next()    返回迭代的下一個元素。 
     void remove()  刪除
         default void forEach 實現了迭代器接口的類才可以使用forEach
}/<code> 

這幾個方法有著很重要的意義:

  1. 所有實現Collection接口(也就是大部分集合)都可以使用forEach功能。
  2. 通過反覆調用next()方法可以訪問集合內的每一個元素。
  3. java迭代器查找的唯一操作就是依靠調用next,而在執行查找任務的同時,迭代器的位置也在改變。
  4. Iterator迭代器remove方法會刪除上次調用next方法返回的元素,這也意味著remove方法和next有著很強的依賴性,如果在調用remove之前沒有調用next是不合法的。

這個接口衍生出了,java集合的迭代器。

Java集合的迭代器使用

下面是迭代器的一個小例子:

<code>class test {
    public static void run() {
        List list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        Iterator iterator = list.iterator();//依靠這個方法生成一個java集合迭代器/<code>

當然你也會有點好奇,為什麼remove方法前面必須跟著一個next方法,其實這個只能這麼解釋。

迭代器的next方法的運行方式並不是類似於數組的運行方式。

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

當然,這張圖主要是讓你理解一下。

數組的指針指向要操作的元素上面,而迭代器卻是將要操作的元素放在運動軌跡中間。

本質來講,迭代器的指針並不是指在元素上,而是指在元素和元素中間。

假設現在調用remove().被刪除的就是2號元素,(被迭代器那個圓弧籠蓋在其中的那個元素),如果再次調用,就會報錯,因為圓弧之中的2號元素已經消失,那裡是空的,無法刪除。

三、Collection接口

這個對象是一個被LIst,Set,Queue的超類,這個接口中的方法,構成了集合中主要的方法和內容。剩下的集合往往都是對這個接口的擴充。

方法如下:

<code>boolean add(E o) 
          確保此 collection 包含指定的元素(可選操作)。 
 boolean addAll(Collection extends E> c) 
          將指定 collection 中的所有元素添加到此 collection 中(可選操作)。 
 void clear() 
          從此 collection 中移除所有元素(可選操作)。 
 boolean contains(Object o) 
          如果此 collection 包含指定的元素,則返回 true。 
 boolean containsAll(Collection> c) 
          如果此 collection 包含指定 collection 中的所有元素,則返回 true。 
 boolean isEmpty() 
          如果此 collection 不包含元素,則返回 true。 
abstract  Iterator iterator() 
          返回在此 collection 中的元素上進行迭代的迭代器。 
 boolean remove(Object o) 
          從此 collection 中移除指定元素的單個實例(如果存在)(可選操作)。 
 boolean removeAll(Collection> c) 
          從此 collection 中移除包含在指定 collection 中的所有元素(可選操作)。 
 boolean retainAll(Collection> c) 
          僅在此 collection 中保留指定 collection 中所包含的元素(可選操作)。 
abstract  int size() 
          返回此 collection 中的元素數。 
 Object[] toArray() 
          返回包含此 collection 中所有元素的數組。 
 T[] toArray(T[] a) 
          返回包含此 collection 中所有元素的數組;返回數組的運行時類型是指定數組的類型。 
 String toString() /<code>

其實我們並不一定要把這些方法都記住

我們只要記住Collection對象實現了這些種類的方法就可以了(可以現查API,不是..

但是確實,這些方法記住了有很大的用處。

<code>添加元素(兩種) 添加一個元素,添加一個集合
刪除元素(三種)  刪除一個元素,刪出一個集合,只保留一個集合
判斷大小
變成數組
是否為空
清空/<code>

1. Java集合的泛型使用

到這裡我們還要講解一個問題,就是除了Map的集合類型(看看上面的繼承表,map是單獨一個分支)都可以傳入Collection為參數的函數里面去.

<code>public class Test {
    public static void  display(Collection> a){
        System.out.println(a);
    }

    public static void main(String[] args) {
        List list=new LinkedList<>();//鏈表
        list.add(1);
        list.add(2);
        list.add(4);
        list.add(3);
        display(list);//[1, 2, 4, 3]
        Set set=new TreeSet<>();//樹集
        set.addAll(list);
        //在這裡之所以兩者輸出不同,是因為樹集有著一個自動排序的功能.其原因在於對於treeset內部結構的實現和LinkedList有所不同
        display(set);//[1, 2, 3, 4]
        
    }
}/<code>

2. Java集合中使用泛型的好處

為什麼在java集合中經常使用泛型。除了為了防止輸入錯誤的數據,更重要的是如果用了泛型也會讓操作更加的方便,省去了強制轉化的過程。

以下兩個是準備

<code>public class AppleAndOrangeWithOutGenerics {
    @SuppressWarnings("unchecked")//這個只能抑制警告信息,用它就不會有警告

    public static void main(String args[]) {
        /**
         * 不用泛型
         */
//        ArrayList apples=new ArrayList();
//        for (int i = 0; i <3 ; i++) {
//            apples.add(new Apple());
        //在ArrayList無論放進去之前是什麼,再放進去之後都會變成Object類型,
//            apples.add(new Orange());
        //會報一個小小的warning,因為沒有使用泛型. apples = new ArrayList();
        for (int i = 0; i  
< 3; i++) { apples.add(new Apple()); // apples.add(new Orange());//在這裡直接就報錯了,讓這種錯誤在編譯期就被發現 } for (int j = 0; j < apples.size(); j++) { //用了反省之後連強制轉換都不需要了 System.out.println(( apples.get(j)).id());//如果沒有泛型的攔截,輸入Orange類型根本不會被發現.非常的危險 } } }/<code>

所以使用泛型有很大的好處。

四、List

List是一個有序集合,元素會增加到容器中特定的位置,可以採用兩種方式訪問元素:使用迭代器訪問或者使用一個整數索引訪問。後一種方式稱為隨機訪問。

為此List接口多定義了一些方法,來實現這一點

<code>void add(int index,E element);//這個和上面不同,帶了index.
void remove(int index);
E get(int index);
E set(int index,E element);/<code>

我們知道實現LIST接口的類中有一個類叫做AbstractList,他的兩個子類分別是LinkedList和ArrayList這兩種。那麼問題是鏈表可不可以使用這個add方法。

答案是可以的,實際上鍊表使用隨機訪問,只不過是慢了點而已。如果有可能,還是使用迭代器為好。

LIST主要有兩種類:一個是LinkedList一個是ArrayList。

1. LinkedList

我們就從一個程序看一看LinkedList到底怎麼用.

<code>/**
 * LinkedLIST也像ArrayList一揚實現了基本的List接口,但是他執行一些操作效率更高,比如插入.
 * LIST為空就會拋出NoSuchElement-Exception
 * Created by 22643 on 2020/4/17.
 */
public class LinkedListFeatures {
    public static void main(String[] args) {
        LinkedList pets=new LinkedList(Pets.arrayList(5));//後面括號中的意思是生成五個Pets對象
        System.out.println("pets = [" + pets + "]");
        System.out.println("pets.getFirst() "+pets.getFirst());//取第一個
        System.out.println("pets.element "+pets.element());//也是取第一個,跟first完全相同.
        //如果列表為空如上兩個內容返回NoSuchElement-Exception
        System.out.println("pets.peek()"+pets.peek());//peek跟上面兩個一揚,只是在列表為空的時候返回null
        System.out.println(pets.removeFirst());
        System.out.println(pets.remove());//這兩個完全一樣,都是移除並返回列表頭,列表空的時候返回NoSuchElement-Exception
        System.out.println(pets.poll());//稍有差異,列表為空的時候返回null
        pets.addFirst(new Rat());//addFirst將一個元素插入頭部,addLast是插到尾部
        System.out.println(pets);
        pets.add(new Rat());//將一個元素插入尾部
        System.out.println(pets);
        pets.offer(new Rat());//與上面一揚,將一個元素插入尾部
        System.out.println(pets);
        pets.set(2,new Rat());//將替換為指定的元素
        System.out.println(pets);
    }

}/<code>

實際上LinkedList有非常多的方法,因為LinkedList是被用來實現多中數據結構的。不但可以實現隊列,甚至還有可以實現棧的相關方法。

我們對此進行分類:

棧相關的操作方法:

<code> E poll() 
          找到並移除此列表的頭(第一個元素)。 
 peek() 
          找到但不移除此列表的頭(第一個元素)。
 void addFirst(E o) 加入開頭可以當作add用/<code>

隊列操作方法:(LinkedList實現了Queue的接口,所以說可以操作用來構建隊列)

注意隊列是FIFO(先進先出)隊列,所以按照實現,從普通隊列是從隊列的尾部插入,從頭部移除。

所以方法如下:

<code>E element() 首元素
boolean offer(E o)將指定隊列插入桶
E peek() 檢索,但是不移除隊列的頭
E pool()檢索並移除此隊列的頭,為空返回null.
E remove()檢索並移除此隊列的頭/<code>

一般來講集合中的方法在移除方法都會有一個為空的時候返回null的方法,和一個為空的時候返回null的方法。類似於pool()和remove()

我們一會到Queue的時候還會將這些再將一次。

2. ArrayList

我們也從一個程序來看這個

<code>public class ListFeatures {
    public static void main(String[] args) {
        Random rand=new Random(47);//相同的種子會產生相同的隨機序列。
        List list=new ArrayList<>();
        list.add("demo3");
        list.add("demo2");
        list.add("demo1");//加入方法
        System.out.println("插入元素前list集合"+list);//可以直接輸出
        /**
         * /void add(int index, E element)在指定位置插入元素,後面的元素都往後移一個元素
         */
        list.add(2,"demo5");
        System.out.println("插入元素前list集合"+list);
        List listtotal=new ArrayList<>();
        List list1=new ArrayList<>();
        List list2=new ArrayList<>();
        list1.add("newdemo1");
        list1.add("newdemo2");
        list1.add("newdemo2");
        /**
         * boolean addAll(int index, Collection extends E> c)
         * 在指定的位置中插入c集合全部的元素,如果集合發生改變,則返回true,否則返回false。
         * 意思就是當插入的集合c沒有元素,那麼就返回false,如果集合c有元素,插入成功,那麼就返回true。
         */
        boolean b=listtotal.addAll(list1);
        boolean c=listtotal.addAll(2,list2);
        System.out.println(b);
        System.out.println(c);//插入2號位置,list2是空的
        System.out.println(list1);
        /**
         * E get(int index)
         * 返回list集合中指定索引位置的元素
         */
        System.out.println(list1.get(1));//list的下標是從0開始的
        /**
         * int indexOf(Object o)
         * 返回list集合中第一次出現o對象的索引位置,如果list集合中沒有o對象,那麼就返回-1
         */
        System.out.println(list1.indexOf("demo"));
        System.out.println(list1.indexOf("newdemo2"));
//如果在list中有相同的數,也沒有問題.
        //但是如果是對象,因為每個對象都是獨一無二的.所以說如果傳入一個新的對象,indexof和remove都是無法完成任務的
        //要是刪除,可以先找到其位置,然後在進行刪除.
        //Pet p=pets.get(2);
        //pets.remove(p);
        /**
         * 查看contains查看參數是否在list中
         */
        System.out.println(list1.contains("newdemo2"));//true
        /**
         * remove移除一個對象
         * 返回true和false
         */
        //只刪除其中的一個
        System.out.println(list1.remove("newdemo2"));//[newdemo1, newdemo2]
        System.out.println(list1);
        List pets=list1.subList(0,1);//讓你從較大的一個list中創建一個片段
        //containall一個list在不在另一個list中
        System.out.println(pets+"在list中嘛"+list1.containsAll(pets));//[newdemo1]在list中嘛true
        //因為sublist的背後就是初始化列表,所以對於sublist的修改會直接反映到原數組上面
        pets.add("new add demo");
        System.out.println(list1);//[newdemo1, new add demo, newdemo2]
        Collections.sort(pets);
        System.out.println(
                pets
        );//new add demo, newdemo1
        System.out.println(list1.containsAll(pets));//true-----變換位置不會影響是否在list1中被找到.
        list1.removeAll(pets);//移除在參數list中的全部數據
        /**
         * list1[newdemo1, new add demo, newdemo2]
         * pets[new add demo, newdemo1]
         */
        System.out.println(list1);//[newdemo2]
        System.out.println(list1.isEmpty());//是否為空
        System.out.println(list1.toArray());//將list變為數組
        //list的addAll方法有一個重載的.可以讓他在中間加入

    }
}/<code> 

這個比較適合非順序存儲。

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

五、Set

Set實際上也是一種映射關係的集合和Map比較像。但是它實現的依然是Collection的接口。

而且Set中的方法和Collection的方法幾乎完全一樣。

唯一的區別在於add方法不允許增加重複的元素,在調用equal時,如果兩個Set中的元素都相等,無論兩者的順序如何,這兩個Set都會相等。

set的特性

<code>Set不保存重複的元素.
Set就是Collection,只是行為不同.
HashSet使用了散列,它打印的時候,輸出的元素不會正常排列
TreeSet使用了儲存在紅黑樹結構中,,所以輸出的元素會正常排列/<code>

當然Set最主要的工作就是判斷存在性,目的是看一個元素到底存不存在這個集合之中。

下面放上兩個Set的例子:

SortedSet(TreeSet)

<code>public class SortedSetOfInteger {
    public static void main(String[] args) {
        Random random=new Random(47);
        SortedSet intset=new TreeSet<>();
        for (int i = 0; i <100 ; i++) {
            intset.add(random.nextInt(30));
        }
        System.out.println(intset);//set特性只能輸入相同的數,別看輸入了100個數,但是實際上只有30個進去了.
        //這個有序了.這就是treeset的功勞,因為內部的實現時紅黑樹,所以來說.這就簡單了一些
    }
}/<code>

HashSet

<code>public class SetOfInteger {
    public static void main(String[] args) {
        Random rand=new Random(47);
        Set intset=new HashSet<>();//創建一個HashSet
        for (int i = 0; i <100 ; i++) {
            intset.add(rand.nextInt(30));
        }
        System.out.println(intset);//set特性只能輸入相同的數,別看輸入了100個數,但是實際上只有30個進去了.
    }
}/<code>

這裡要講一下HashSet。HashSet不在意元素的順序,根據屬性可以快速的訪問所需要的對象。散列表為每個對象計算一個整數,成為散列碼...散列碼是實例產生的一個整數。

散列表(HashSet)散列表用鏈表數組實現。每個列表稱為通。想要查找表中對象的位置就計算它的散列碼。然後與通的總數取餘,得到的數就是保存這個元素的通的索引。

但是桶總有被沾滿的一刻。

為了應對這種情況,需要用新對象與桶中所有對象比較,看是否存在。

為了控制性能就要能定義初始桶數,設置為要插入元素的75%-150%,最好為素數。

這個時候就要執行再散列,讓這個散列表獲得更多的內容。

再散列:

需要創建一個桶數更多的表,並將全部元素插入這個新表中。裝填因子絕對什麼時候在執行,如果裝填因子為0.75那麼就是在表中75%的位置被佔滿時,表會給如雙倍的桶數自動散列。

1. Queue

隊列是數據結構中比較重要的一種類型,它支持 FIFO,尾部添加、頭部刪除(先進隊列的元素先出隊列),跟我們生活中的排隊類似。

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

但是在集合中的Queue並沒有單獨的實現類,而是用LinkedList實現的。其實你只要看一眼LinkedList的方法就知道,他完全可以實現隊列的操作。

<code>add()尾部添加
removeFirst()刪除頭部元素
peek()查看頭部元素/<code>

Queue主要有兩種不同的類型。

分別是優先級隊列和Deque隊列

2. PriorityQueue

優先級隊列中元素可以按照任意的順序插入,卻按照目標排序的順序進行檢索,也就是無論什麼時候調用remove移除的都是當前最小的元素。

優先級使用了一種堆,一個可以自我調節的二叉樹,對樹進行執行添加和刪除。它可以讓最小的元素移動到跟,而不必花時間對其排序。

當然,你也可以自己對其進行排序.

舉例:

<code>import java.text.DecimalFormat;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;

/**
 * @Author:sks
 * @Description:
 * @Date:Created in 10:39 2018/1/11
 * @Modified by:
 **/

//二維平面上一個點
 class point {
    //座標x
    double x;

    //座標y
    double y;
    public point(double x, double y){
        this.x = x;
        this.y = y;
    }
}
//排序函數
class PointComparator {
    private   point pointOne;
    private point pointTwo;
    public double distance;
    public PointComparator(point pointOne,point pointTwo)
    {
        this.pointOne = pointOne;
        this.pointTwo = pointTwo;
        computeDistance();
    }
    //計算兩點之間距離
    private void computeDistance() {
        double val = Math.pow((this.pointOne.x - this.pointTwo.x),2) +
                Math.pow((this.pointOne.y - this.pointTwo.y),2);
        this.distance = Math.sqrt(val);
    }


}
public class PriorityQueuep_test {

    public static void main(String args[]){
         Comparator OrderDistance =  new Comparator(){
            public int compare(PointComparator one, PointComparator two) {
                if (one.distance < two.distance)
                    return 1;
                else if (one.distance > two.distance)
                    return -1;
                else
                    return 0;
            }
        };

        //定義一個優先隊列,用來排序任意兩點之間的距離,從大到小排
        Queue FsQueue = new PriorityQueue(10,OrderDistance);

        for (int i=0;i<6;i++){

            java.util.Random r= new java.util.Random(10);
            point one =new point(i*2+1,i*3+2);
            point two =new point(i*5+2,i*6+3);
            PointComparator nodecomp = new PointComparator(one,two);

            DecimalFormat df = new DecimalFormat("#.##");
            FsQueue.add(nodecomp);
        }
        DecimalFormat df = new DecimalFormat("#.###");
        for (int i = 0;i<6;i++){
            System.out.println(df.format(FsQueue.poll().distance));
        }
    }

}/<code>

3. Deque

deque也有些複雜,它可以用ArrayDeque實現,也可以用LinkedList實現。

線性集合,支持兩端的元素插入和移除。Deque是double ended queue的簡稱,習慣上稱之為雙端隊列。大多數Deque 實現對它們可能包含的元素的數量沒有固定的限制,但是該接口支持容量限制的deques以及沒有固定大小限制的deque。

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

因為本身也是LinkedList實現的,所以其本身的方法和LinkedList差不了多少。

舉例:

<code>public class Main {
    public static void main(String[] args) {
        Deque deque = new LinkedList<>();
        deque.offerLast("A"); // A
        deque.offerLast("B"); // B -> A
        deque.offerFirst("C"); // B -> A -> C
        System.out.println(deque.pollFirst()); // C, 剩下B -> A
        System.out.println(deque.pollLast()); // B
        System.out.println(deque.pollFirst()); // A
        System.out.println(deque.pollFirst()); // null
    }
}/<code>

4. Stack

stack的名字大家都知道,就是棧.一個先進後出的數據結構,這裡我並不認為應該使用java集合中提供的棧集合.

而是應該使用LinkedList來構建集合:一個小任務:

用LinkedList實現棧

<code>public class Stack {
    private LinkedList storage=new LinkedList<>();//用LinkedList作為棧的核心
    public void push(T v){ storage.addFirst(v);}//
    public T peek(){ return storage.getFirst();}
    public T pop(){return storage.removeFirst();}
    public boolean empty(){return storage.isEmpty();}
    public String toString(){return storage.toString();}
}/<code>

這樣做有一個好處,就是這樣的棧可以有更多種的方法,可以採用更多種的方式。無疑這樣的棧會更好一些。

所以我推薦大家用棧的時候,用LinkedList來實現。

5. MAP

講了Collection接口實現的各種集合,我們就要講講非Collection的集合。這意味著你在Collection中記住的方法在這個裡面完全用不到了。

我們知道一些鍵的信息,想要知道與之對應的元素。映射結構就是為此設計的,映射用來存放鍵值對,如提供了鍵就能查到值。

[萬字長文]阿里架構師突擊總結:java集合的核心知識盡攬其中

和Set一樣,HashMap要比TreeMap要快上一些,但是TreeMap有序。這與Set很相似,畢竟Set其實也是映射結構。

每當往映射加入對象是,必須同時提供一個鍵。

鍵是唯一的,不能對同一個鍵放兩個值。如果對同一個鍵調用兩次put方法,第二次調用會取代第一個。

要想處理所有的鍵和值,那就應該使用foreach

列子如下:

<code>public class MapOfList {
    public static Map> people=new HashMap<>();
    static {
        people.put(new Person("dawn"), Arrays.asList(new Cymric("Molly"),new Mutt("Spot")));
        //就寫一個了,有點懶了.
    }
    public static void main(String[] args) {
        System.out.println(people.keySet());//返回的是鍵組成的set
        System.out.println(people.values());//返回的時值組成的set
        for (Person person:people.keySet()
             ) {
            System.out.println(person+"has :");
            for (Pet pet:people.get(person)
                 ) {
                System.out.println(pet);

            }
        }
    }
}/<code>

下面還有一個HashMap使用的例子

<code>public class PetMap {
    public static void main(String[] args) {
        Map petMap=new HashMap();
        petMap.put("My Cat",new Cat("MALL"));
        petMap.put("My Dog",new Dog("DOGGY"));
        petMap.put("My Haster",new Hamster("Bosco"));
        System.out.println(petMap);
        Pet dog=petMap.get("My Dog");
        System.out.println(dog);
        System.out.println(petMap.containsKey("My Dog"));//
        System.out.println(petMap.containsValue(dog));//
    }
}/<code>

推薦閱讀:

太狠了!京東T8架構師建議吃透這40W字消息隊列文檔,漲薪15K不是夢

RocketMQ全貌解析,阿里不愧是阿里

為什麼大廠的面試題問的都是底層原理,前阿里P7架構師是這樣說的

java開發必知必會的技能,沒有系統掌握Kafka,你就缺少核心競爭力

2020還不會性能調優?啃下這20W字Java性能調優筆記,隨便漲薪13K!


分享到:


相關文章: