1. 程式人生 > 實用技巧 >Java集合知識點總結

Java集合知識點總結

來源於部落格園,csdn,b站等各大知識分享平臺,只是整理方便自己複習,沒有任何商用,有問題聯絡立馬刪除!

集合的概述
集合:集合是java中提供的一種容器,可以用來儲存多個數據。java.util包下
集合與陣列的區別:
* 陣列的長度是固定的。集合的長度是可變的。
* 陣列中儲存的是同一型別的元素,可以儲存基本資料型別值。集合儲存的都是物件。而且物件的型別可以不一致。在開發中一般當物件多的時候,使用集合進行儲存。
集合的體系圖:

Collection:單列集合類的根介面,用於儲存一系列符合某種規則的元素,它有兩個重要的子介面,分別是java.util.Listjava.util.Set

。其中,List的特點是元素有序、元素可重複。Set的特點是元素無序,而且不可重複。List介面的主要實現類有java.util.ArrayListjava.util.LinkedListSet介面的主要實現類有java.util.HashSetjava.util.TreeSet

那麼根據上面的圖進行自頂向下去分析:
Collection介面時所有單列集合的父介面,因此定義了一些方法可以滿足使用,(list和set通用),注意:操作的僅僅是單列集合。

  • public boolean add(E e): 把給定的物件新增到當前集合中 。
  • public void clear() :清空集合中所有的元素。
  • public boolean remove(E e): 把給定的物件在當前集合中刪除。
  • public boolean contains(E e): 判斷當前集合中是否包含給定的物件。
  • public boolean isEmpty(): 判斷當前集合是否為空。
  • public int size(): 返回集合中元素的個數。
  • public Object[] toArray(): 把集合中的元素,儲存到陣列中。

建立集合以多型的形式進行建立,用ArrayList作為其實現類去使用

Collection<String> coll = new ArrayList<String>();

新增元素:
coll.add();
輸出集合:
System.out.println(coll);

之前也說過,直接輸出說明重寫了toString方法,

迭代器(Iterator)

在程式開發中,經常需要遍歷集合中的所有元素。針對這種需求,JDK專門提供了一個介面java.util.IteratorIterator介面也是Java集合中的一員,但它與CollectionMap介面有所不同,Collection介面與Map介面主要用於儲存元素,而Iterator主要用於迭代訪問(即遍歷)Collection中的元素,因此Iterator物件也被稱為迭代器。

Iterator是一個介面,所以每個集合都存在這個方法生成一個迭代器。
public Iterator iterator(): 獲取集合對應的迭代器,用來遍歷集合中的元素的。

迭代:即Collection集合元素的通用獲取方式。在取元素之前先要判斷集合中有沒有元素,如果有,就把這個元素取出來,繼續在判斷,如果還有就再取出出來。一直把集合中的所有元素全部取出。這種取出方式專業術語稱為迭代。

常用的方法如下所示:
* public E next():返回迭代的下一個元素。
* public boolean hasNext():如果仍有元素可以迭代,則返回 true。

使用:

Iterator<String> it = coll.iterator();//  泛型指的是 迭代出 元素的資料型別
        while(it.hasNext()){ //判斷是否有迭代元素
            String s = it.next();//獲取迭代出的元素
            System.out.println(s);
        }

如果使用next()後沒有元素,會報出java.util.NoSuchElementException沒有集合元素的錯誤。

關於迭代器的實現原理可以閱讀更高階的jvm書籍或者Java書籍去獲得,作者也並未深究,因為目前的還沒學習完
如果學過c,你可以理解成指標,它的內部就是指標進行的,如果不好理解就可以用連結串列相關的去進行一個理解。後續補上····

這裡關於遍歷,除了while,for,dowhile還有一種,foreach,也就是增強for
格式:

for(元素的資料型別  變數 : Collection集合or陣列){ 
  	//寫操作程式碼
}

它用於遍歷Collection和陣列。通常只進行遍歷元素,不要在遍歷的過程中對集合元素進行增刪操作。


int[] arr = {3,5,6,87};
		for(int a : arr){//a代表陣列中的每個元素
			System.out.println(a);
		}

1.2##泛型
概念:
* 泛型:可以在類或方法中預支地使用未知的型別。

tips:一般在建立物件時,將未知的型別確定具體的型別。當沒有指定泛型時,預設型別為Object型別。

定義格式:

修飾符 class 類名<代表泛型的變數> {  }

例如,API中的ArrayList集合:

class ArrayList<E>{ 
    public boolean add(E e){ }

    public E get(int index){ }
   	....
}

使用泛型: 即什麼時候確定泛型。

在建立物件的時候確定泛型

例如,ArrayList<String> list = new ArrayList<String>();

此時,變數E的值就是String型別,那麼我們的型別就可以理解為:

class ArrayList<String>{ 
     public boolean add(String e){ }

     public String get(int index){  }
     ...
}

再例如,ArrayList<Integer> list = new ArrayList<Integer>();

此時,變數E的值就是Integer型別,那麼我們的型別就可以理解為:

class ArrayList<Integer> { 
     public boolean add(Integer e) { }

     public Integer get(int index) {  }
     ...
}

舉例自定義泛型類

public class MyGenericClass<MVP> {//沒有MVP型別,在這裡代表 未知的一種資料型別 未來傳遞什麼就是什麼型別
	private MVP mvp;
     
    public void setMVP(MVP mvp) {
        this.mvp = mvp;
    }
     
    public MVP getMVP() {
        return mvp;
    }
}

使用:

public class GenericClassDemo {
  	public static void main(String[] args) {// 建立一個泛型為String的類
         MyGenericClass<String> my = new MyGenericClass<String>();    	// 呼叫setMVP
         my.setMVP("大鬍子登登");// 呼叫getMVP
         String mvp = my.getMVP();
         System.out.println(mvp);//建立一個泛型為Integer的類
         MyGenericClass<Integer> my2 = new MyGenericClass<Integer>(); 
         my2.setMVP(123);   	  
         Integer mvp2 = my2.getMVP();
    }
}

含有泛型的方法

定義格式:

修飾符 <代表泛型的變數> 返回值型別 方法名(引數){  }

  public <MVP> void show(MVP mvp) {
    	System.out.println(mvp.getClass());
    }
    
    public <MVP> MVP show2(MVP mvp) {	
    	return mvp;
    }
  public static void main(String[] args) {
        // 建立物件
        MyGenericMethod mm = new MyGenericMethod();
        // 演示看方法提示
        mm.show("aaa");
        mm.show(123);
        mm.show(12.45);
    }

含有泛型的介面

定義格式:

修飾符 interface介面名<代表泛型的變數> {  }

同上

1.2.1####泛型萬用字元
當使用泛型類或者介面時,傳遞的資料中,泛型型別不確定,可以通過萬用字元<?>表示。但是一旦使用泛型的萬用字元後,只能使用Object類中的共性方法,集合中元素自身方法無法使用。

萬用字元基本使用

泛型的萬用字元:不知道使用什麼型別來接收的時候,此時可以使用? ?表示未知萬用字元。


public static void main(String[] args) {
    Collection<Intger> list1 = new ArrayList<Integer>();
    getElement(list1);
    Collection<String> list2 = new ArrayList<String>();
    getElement(list2);
}
public static void getElement(Collection<?> coll){}

泛型不存在繼承關係 Collection list = new ArrayList();這種是錯誤的。

萬用字元高階使用----受限泛型

之前設定泛型的時候,實際上是可以任意設定的,只要是類就可以設定。但是在JAVA的泛型中可以指定一個泛型的上限下限

泛型的上限

  • 格式型別名稱 <? extends 類 > 物件名稱
  • 意義只能接收該型別及其子類

泛型的下限

  • 格式型別名稱 <? super 類 > 物件名稱
  • 意義只能接收該型別及其父型別

比如:現已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類

public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement(list1);
    getElement(list2);//報錯
    getElement(list3);
    getElement(list4);//報錯
  
    getElement2(list1);//報錯
    getElement2(list2);//報錯
    getElement2(list3);
    getElement2(list4);
  
}
// 泛型的上限:此時的泛型?,必須是Number型別或者Number型別的子類
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此時的泛型?,必須是Number型別或者Number型別的父類
public static void getElement2(Collection<? super Number> coll){}

List集合介面

api文件中的介紹:

java.util.List介面繼承自Collection介面,是單列集合的一個重要分支,習慣性地會將實現了List介面的物件稱為List集合。在List集合中允許出現重複的元素,所有的元素是以一種線性方式進行儲存的,在程式中可以通過索引來訪問集合中的指定元素。另外,List集合還有一個特點就是元素有序,即元素的存入順序和取出順序一致。

List集合的特點:

  1. 它是一個元素存取有序的集合。例如,存元素的順序是11、22、33。那麼集合中,元素的儲存就是按照11、22、33的順序完成的)。
  2. 它是一個帶有索引的集合,通過索引就可以精確的操作集合中的元素(與陣列的索引是一個道理)。
  3. 集合中可以有重複的元素,通過元素的equals方法,來比較是否為重複的元素。

常用的方法:

  • public void add(int index, E element): 將指定的元素,新增到該集合中的指定位置上。
  • public E get(int index):返回集合中指定位置的元素。
  • public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
  • public E set(int index, E element):用指定元素替換集合中指定位置的元素,返回值的更新前的元素。

List的子類

  ####ArrayList集合

java.util.ArrayList集合資料儲存的結構是陣列結構。元素增刪慢,查詢快,由於日常開發中使用最多的功能為查詢資料、遍歷資料,所以ArrayList是最常用的集合。

  ####LinkedList集合

java.util.LinkedList集合資料儲存的結構是連結串列結構。方便元素新增、刪除的集合
它是一個雙向連結串列:

常用方法:

  • public void addFirst(E e):將指定元素插入此列表的開頭。
  • public void addLast(E e):將指定元素新增到此列表的結尾。
  • public E getFirst():返回此列表的第一個元素。
  • public E getLast():返回此列表的最後一個元素。
  • public E removeFirst():移除並返回此列表的第一個元素。
  • public E removeLast():移除並返回此列表的最後一個元素。
  • public E pop():從此列表所表示的堆疊處彈出一個元素。
  • public void push(E e):將元素推入此列表所表示的堆疊。
  • public boolean isEmpty():如果列表不包含元素,則返回true。

在linkedList和ArrayList中都可以使用List和Collection的方法,因為他們都是子類

Set介面

API文件介紹:

java.util.Set介面和java.util.List介面一樣,同樣繼承自Collection介面,它與Collection介面中的方法基本一致,並沒有對Collection介面進行功能上的擴充,只是比Collection介面更加嚴格了。與List介面不同的是,Set介面中元素無序,並且都會以某種規則保證存入的元素不出現重複。

Set集合取出元素,使用迭代器和增強for

HashSet集合

API文件:

java.util.HashSetSet介面的一個實現類,它所儲存的元素是不可重複的,並且元素都是無序的(即存取順序不一致)。java.util.HashSet底層的實現其實是一個java.util.HashMap支援

HashSet是根據物件的雜湊值來確定元素在集合中的儲存位置,因此具有良好的存取和查詢效能。保證元素唯一性的方式依賴於:hashCodeequals方法。

public static void main(String[] args) {
        //建立 Set集合
        HashSet<String>  set = new HashSet<String>();

        //新增元素
        set.add(new String("cba"));
        set.add("abc");
        set.add("bac"); 
        set.add("cba");  
        //遍歷
        for (String name : set) {
            System.out.println(name);
        }
    }

結果:

      cba
      abc
      bac

HashSet集合儲存結構雜湊表:

JDK1.8之前,雜湊表底層採用陣列+連結串列實現,即使用連結串列處理衝突,同一hash值的連結串列都儲存在一個連結串列裡。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查詢的效率較低。而JDK1.8中,雜湊表儲存採用陣列+連結串列+紅黑樹實現,當連結串列長度超過閾值(8)時,將連結串列轉換為紅黑樹,這樣大大減少了查詢時間。

雜湊表的構成:

雜湊表是由陣列+連結串列+紅黑樹(JDK1.8增加了紅黑樹部分)實現的

DK1.8**引入紅黑樹大程度優化了HashMap的效能,那麼對於我們來講保證HashSet集合元素的唯一,其實就是根據物件的hashCode和equals方法來決定的。如果我們往集合中存放自定義的物件,那麼保證其唯一,就必須複寫hashCode和equals方法建立屬於當前物件的比較方式。

HashSet儲存自定義型別

給HashSet中存放自定義型別元素時,需要重寫物件中的hashCode和equals方法,建立自己的比較方式,才能保證HashSet集合中的物件唯一

LinkedHashSet

在HashSet下面有一個子類java.util.LinkedHashSet,它是連結串列和雜湊表組合的一個數據儲存結構。
例項:

public static void main(String[] args) {
		Set<String> set = new LinkedHashSet<String>();
		set.add("bbb");
		set.add("aaa");
		set.add("abc");
		set.add("bbc");
        Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
結果:
  bbb
  aaa
  abc
  bbc

可變引數:
JDK1.5之後,如果我們定義一個方法需要接受多個引數,並且多個引數型別一致,我們可以對其簡化成如下格式:

修飾符 返回值型別 方法名(引數型別... 形參名){  }

其實這個書寫完全等價與

修飾符 返回值型別 方法名(引數型別[] 形參名){  }

只是後面這種定義,在呼叫時必須傳遞陣列,而前者可以直接傳遞資料即可。

JDK1.5以後。出現了簡化操作。... 用在引數上,稱之為可變引數。

同樣是代表陣列,但是在呼叫這個帶有可變引數的方法時,不用建立陣列(這就是簡單之處),直接將陣列中的元素作為實際引數進行傳遞,其實編譯成的class檔案,將這些元素先封裝到一個數組中,在進行傳遞。這些動作都在編譯.class檔案時,自動完成了。

注意:如果在方法書寫時,這個方法擁有多引數,引數中包含可變引數,可變引數一定要寫在引數列表的末尾位置。

工具類Collections

基本概念:
java.utils.Collections是集合工具類,用來對集合進行操作。
常用:

  • public static <T> boolean addAll(Collection<T> c, T... elements) :往集合中新增一些元素。
  • public static void shuffle(List<?> list) 打亂順序:打亂集合順序。
  • public static <T> void sort(List<T> list):將集合中元素按照預設規則排序。
  • public static <T> void sort(List<T> list,Comparator<? super T> ):將集合中元素按照指定規則排序。

主要說明按規則排序sort

Comparator比較器
public static <T> void sort(List<T> list,Comparator<? super T> )方法靈活的完成,這個裡面就涉及到了Comparator這個介面,位於位於java.util包下,排序是comparator能實現的功能之一,該介面代表一個比較器,比較器具有可比性!顧名思義就是做排序的,通俗地講需要比較兩個物件誰排在前誰排在後,那麼比較的方法就是:

  • public int compare(String o1, String o2):比較其兩個引數的順序。

    兩個物件比較的結果有三種:大於,等於,小於。

    如果要按照升序排序,
    則o1 小於o2,返回(負數),相等返回0,01大於02返回(正數)
    如果要按照降序排序
    則o1 小於o2,返回(正數),相等返回0,01大於02返回(負數)

操作如下:

public class CollectionsDemo3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("cba");
        list.add("aba");
        list.add("sba");
        list.add("nba");
        //排序方法  按照第一個單詞的降序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.charAt(0) - o1.charAt(0);
            }
        });
        System.out.println(list);
    }
}

結果如下:

[sba, nba, cba, aba]

Comparable:強行對實現它的每個類的物件進行整體排序。這種排序被稱為類的自然排序,類的compareTo方法被稱為它的自然比較方法。只能在類中實現compareTo()一次,不能經常修改類的程式碼實現自己想要的排序。實現此介面的物件列表(和陣列)可以通過Collections.sort(和Arrays.sort)進行自動排序,物件可以用作有序對映中的鍵或有序集合中的元素,無需指定比較器。

Comparator強行對某個物件進行整體排序。可以將Comparator 傳遞給sort方法(如Collections.sort或 Arrays.sort),從而允許在排序順序上實現精確控制。還可以使用Comparator來控制某些資料結構(如有序set或有序對映)的順序,或者為那些沒有自然順序的物件collection提供排序。

Map集合介面:

現實生活中,我們常會看到這樣的一種集合:IP地址與主機名,身份證號與個人,系統使用者名稱與系統使用者物件等,這種一一對應的關係,就叫做對映。Java提供了專門的集合類用來存放這種物件關係的物件,即java.util.Map介面。

  • ollection`中的集合,元素是孤立存在的(理解為單身),向集合中儲存元素採用一個個元素的方式儲存。
  • Map中的集合,元素是成對存在的(理解為夫妻)。每個元素由鍵與值兩部分組成,通過鍵可以找對所對應的值。
  • Collection中的集合稱為單列集合,Map中的集合稱為雙列集合。
  • 需要注意的是,Map中的集合不能包含重複的鍵,值可以重複;每個鍵只能對應一個值。

常用子類:

  • HashMap<K,V>:儲存資料採用的雜湊表結構,元素的存取順序不能保證一致。由於要保證鍵的唯一、不重複,需要重寫鍵的hashCode()方法、equals()方法。
  • LinkedHashMap<K,V>:HashMap下有個子類LinkedHashMap,儲存資料採用的雜湊表結構+連結串列結構。通過連結串列結構可以保證元素的存取順序一致;通過雜湊表結構可以保證的鍵的唯一、不重複,需要重寫鍵的hashCode()方法、equals()方法。

Map介面中的集合都有兩個泛型變數<K,V>,在使用時,要為兩個泛型變數賦予資料型別。兩個泛型變數<K,V>的資料型別可以相同,也可以不同。

常用方法:

  • public V put(K key, V value): 把指定的鍵與指定的值新增到Map集合中。
  • public V remove(Object key): 把指定的鍵 所對應的鍵值對元素 在Map集合中刪除,返回被刪除元素的值。
  • public V get(Object key) 根據指定的鍵,在Map集合中獲取對應的值。
  • boolean containsKey(Object key) 判斷集合中是否包含指定的鍵。
  • public Set<K> keySet(): 獲取Map集合中所有的鍵,儲存到Set集合中。
  • public Set<Map.Entry<K,V>> entrySet(): 獲取到Map集合中所有的鍵值對物件的集合(Set集合)。

使用put方法時,若指定的鍵(key)在集合中沒有,則沒有這個鍵對應的值,返回null,並把指定的鍵值新增到集合中;

若指定的鍵(key)在集合中存在,則返回值為集合中鍵對應的值(該值為替換前的值),並把指定鍵所對應的值,替換成指定的新值。

Map集合中遍歷找值的方式

鍵找值方式:即通過元素中的鍵,獲取鍵所對應的值

分析步驟:

  1. 獲取Map中所有的鍵,由於鍵是唯一的,所以返回一個Set集合儲存所有的鍵。方法提示:keyset()
  2. 遍歷鍵的Set集合,得到每一個鍵。
  3. 根據鍵,獲取鍵所對應的值。方法提示:get(K key)
public static void main(String[] args) {
        //建立Map集合物件 
        HashMap<String, String> map = new HashMap<String,String>();
        //新增元素到集合 
        map.put("胡歌", "霍建華");
        map.put("郭德綱", "于謙");
        map.put("薛之謙", "大張偉");

        //獲取所有的鍵  獲取鍵集
        Set<String> keys = map.keySet();
        // 遍歷鍵集 得到 每一個鍵
        for (String key : keys) {
          	//key  就是鍵
            //獲取對應值
            String value = map.get(key);
            System.out.println(key+"的CP是:"+value);
        }  
    }

Entry鍵值找值方式

我們已經知道,Map中存放的是兩種物件,一種稱為key(鍵),一種稱為value(值),它們在在Map中是一一對應關係,這一對物件又稱做Map中的一個Entry(項)Entry將鍵值對的對應關係封裝成了物件。即鍵值對物件,這樣我們在遍歷Map集合時,就可以從每一個鍵值對(Entry)物件中獲取對應的鍵與對應的值。

既然Entry表示了一對鍵和值,那麼也同樣提供了獲取對應鍵和對應值得方法:

  • public K getKey():獲取Entry物件中的鍵。
  • public V getValue():獲取Entry物件中的值。

在Map集合中也提供了獲取所有Entry物件的方法:

  • public Set<Map.Entry<K,V>> entrySet(): 獲取到Map集合中所有的鍵值對物件的集合(Set集合)。

鍵值對方式:即通過集合中每個鍵值對(Entry)物件,獲取鍵值對(Entry)物件中的鍵與值。

操作步驟:

  1. 獲取Map集合中,所有的鍵值對(Entry)物件,以Set集合形式返回。方法提示:entrySet()

  2. 遍歷包含鍵值對(Entry)物件的Set集合,得到每一個鍵值對(Entry)物件。

  3. 通過鍵值對(Entry)物件,獲取Entry物件中的鍵與值。 方法提示:getkey() getValue()

        Set<Entry<String,String>> entrySet = map.entrySet();// 獲取 所有的 entry物件  entrySet
        for (Entry<String, String> entry : entrySet) { // 遍歷得到每一個entry物件
            String key = entry.getKey();
            String value = entry.getValue();  
            System.out.println(key+"的CP是:"+value);

Map集合不能直接使用迭代器或者foreach進行遍歷。但是轉成Set之後就可以使用了。

HashMap儲存自定義鍵值

重寫hashcode方法和equals方法確保key唯一,不重複

LinkHashMap

在HashMap下面有一個子類LinkedHashMap,它是連結串列和雜湊表組合的一個數據儲存結構。
確保有序且速度快

JDK9對集合新增的優化

通常,我們在程式碼中建立一個集合(例如,List 或 Set ),並直接用一些元素填充它。 例項化集合,幾個 add方法 呼叫,使得程式碼重複。

public class Demo01 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("abc");
        list.add("def");
        list.add("ghi");
        System.out.println(list);
    }
}

Java 9,添加了幾種集合工廠方法,更方便建立少量元素的集合、map例項。新的List、Set、Map的靜態工廠方法可以更方便地建立集合的不可變例項。

例子:

public class HelloJDK9 {  
    public static void main(String[] args) {  
        Set<String> str1=Set.of("a","b","c");  
        //str1.add("c");這裡編譯的時候不會錯,但是執行的時候會報錯,因為是不可變的集合  
        System.out.println(str1);  
        Map<String,Integer> str2=Map.of("a",1,"b",2);  
        System.out.println(str2);  
        List<String> str3=List.of("a","b");  
        System.out.println(str3);  
    }  
} 

需要注意以下兩點:

1:of()方法只是Map,List,Set這三個介面的靜態方法,其父類介面和子類實現並沒有這類方法,比如 HashSet,ArrayList等待;

2:返回的集合是不可變的;