java集合詳解


1.java集合是什么?

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

img

集合體系

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

但是真相並不是如此的簡單.

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

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

Collection中需要實現的的方法:

 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<E> 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> T[] toArray(T[] a) 
          返回包含此 collection 中所有元素的數組;返回數組的運行時類型與指定數組的運行時類型相同。 

AbstractCollection類實現的方法:


 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<E> 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> T[] toArray(T[] a) 
          返回包含此 collection 中所有元素的數組;返回數組的運行時類型是指定數組的類型。 
 String toString() 
          返 

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

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

集合類的構建框架如下.
image.png

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

img

這是完整的構建圖.

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

如下是本文的目錄:

(一) Iterator接口--迭代器

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

    

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

  1. 所有實現Collection接口(也就是大部分集合)都可以使用forEach功能.

  2. 通過反復調用next()方法可以訪問集合內的每一個元素.

  3. java迭代器查找的唯一操作就是依靠調用next,而在執行查找任務的同時,迭代器的位置也在改變.

  4. Iterator迭代器remove方法會刪除上次調用next方法返回的元素.這也意味之remove方法和next有着很強的依賴性.如果在調用remove之前沒有調用next是不合法的.

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


    java集合的迭代器使用

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

class test {
    public static void run() {
        List<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        Iterator<Integer> iterator = list.iterator();//依靠這個方法生成一個java集合迭代器<--在Colletion接口中的方法,被所有集合實現.
//        iterator.remove();報錯java.lang.IllegalStateException
        iterator.next();
        iterator.remove();//不報錯,刪掉了1
        System.out.println(list);//AbstractCollection類中實現的toString讓list可以直接被打印出來
        while (iterator.hasNext()) {//迭代器,hasNext()集合是否為空
            Integer a = iterator.next();//可以用next訪問每一個元素
            System.out.println(a);//2,3 ,3
        }
        for (int a : list) {//也可以使用foreach
            System.out.println(a);//2,3,3
        }
    }
    public static void main(String[] args) {
        run();
    }
}

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

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

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

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

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

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

(二) Collection接口

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

方法如下:

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<E> 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> T[] toArray(T[] a) 
          返回包含此 collection 中所有元素的數組;返回數組的運行時類型是指定數組的類型。 
 String toString() <--很重要
          返 

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

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

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

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

java集合的泛型使用

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

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

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

java集合中使用泛型的好處

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

以下兩個是准備

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,因為沒有使用泛型.<-只有刪掉這個句子執行才不報錯
//        }
//            for (int j = 0; j <apples.size() ; j++) {
//                System.out.println(((Apple)apples.get(j)).id());
        //如果沒有泛型的攔截,輸入Orange類型根本不會被發現.非常的危險
//            }

        /**
         * 使用泛型
         */
        ArrayList<Apple> 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類型根本不會被發現.非常的危險
        }
    }
}

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


(三) List

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

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

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

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

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

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

LinkedList

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

/**
 * LinkedLIST也像ArrayList一揚實現了基本的List接口,但是他執行一些操作效率更高,比如插入.
 * LIST為空就會拋出NoSuchElement-Exception
 * Created by 22643 on 2020/4/17.
 */
public class LinkedListFeatures {
    public static void main(String[] args) {
        LinkedList<Pet> pets=new LinkedList<Pet>(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);
    }

}

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

我們對此進行分類:

棧相關的操作方法:

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

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

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

所以方法如下:

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

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

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

ArrayList

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

public class ListFeatures {
    public static void main(String[] args) {
        Random rand=new Random(47);//相同的種子會產生相同的隨機序列。
        List<String> 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<String> listtotal=new ArrayList<>();
        List<String> list1=new ArrayList<>();
        List<String> 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<String> 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方法有一個重載的.可以讓他在中間加入

    }
}

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


(四)(五)Set

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

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

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

set的特性

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

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

下面放上兩個Set的例子:

SortedSet(TreeSet)

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

HashSet

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

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

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

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

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

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

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

再散列:

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

Queue

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

這里寫圖片描述

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

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

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

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

PriorityQueue

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

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

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

小栗子:

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<PointComparator> OrderDistance =  new Comparator<PointComparator>(){
            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<PointComparator> FsQueue = new PriorityQueue<PointComparator>(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));
        }
    }

}

Deque

deque也有些復雜,它可以用ArrayDeque實現,也可以用LinkedList實現.

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

作者:我是吸血鬼
鏈接:https://www.jianshu.com/p/d78a7c982edb
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

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

小栗子:

public class Main {
    public static void main(String[] args) {
        Deque<String> 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
    }
}

Stack

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

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

用LinkedList實現棧

public class Stack<T> {
    private LinkedList<T> 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();}
}

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

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

MAP

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

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

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

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

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

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

列子如下:

public class MapOfList {
    public static Map<Person, List<? extends Pet>> 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);

            }
        }
    }
}

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

public class PetMap {
    public static void main(String[] args) {
        Map<String, Pet> petMap=new HashMap<String, Pet>();
        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));//
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM