Java 集合和泛型


  一、集合(Collections)

  Java使用集合來組織和管理對象。

  1、Java的集合類

  集合類主要負責保存、盛裝和管理對象,因此集合類也被稱為容器類。

  集合類分為Set、List、Map和Queue四大體系。

  • Set 代表無序、不可重復集合;
  • List 代表有序、可重復集合;
  • Map 代表具有映射關系元素的集合;
  • Queue 代表隊列,實現元素的先進先出管理。

  數組也是一種集合類,它是能隨機存儲和訪問引用序列的諸多方法中最高效的一種,當追求高效的數據訪問時,數組是很不錯的選擇。

 

  2、集合與泛型

  所有集合類都位於java.util包中,集合中只能保存對象的引用。集合類把它所含有的元素看成是Object的實例,這樣方便但是也有隱患,即多個類型不同的元素被放入一個集合中,會增加集合訪問時類型轉換的困難,甚至會產生錯誤。

  泛型的引入改善了這種情況,使用泛型來限制集合里元素的類型,並讓集合記住元素的類型。這樣可以允許編譯器檢查加入集合的元素類型,避免值類型不一致的錯誤。

 

  3、Java集合框架介紹

  集合框架是一個用來表示和操作集合的統一架構,包含實現集合的接口和類。

  Java的整個集合框架圍繞一組標准接口設計,開發者可以直接使用這些接口的標准實現,也可以使用集合框架接口實現自定義的集合實現類。

  集合框架的設計應滿足一下三個目標:

  • 高性能。保證算法的實現效率。
  • 互操作性。
  • 高擴展性。對集合進行擴展是簡單的,只需要實現特定接口即可。

  

  4、Java集合框架基於統一的方式組織和管理對象,包含3個方面:

  • 接口。接口定義了集合操作的行為規約,它形成集合的高層視圖。
  • 實現類。是集合接口的具體表現。本質上說,是可重復使用的數據結構。
  • 算法。實現集合操作中常用的算法,比如搜索和排序。這些算法通過多態實現,即相同的方法在相似的接口上有着不同的實現

 

  5、集合接口

  集合框架定義了一組接口,接口申明了對特定類型的集合可以執行的操作。

  Java的集合類主要由兩個接口派生而出——CollectionMap,它們是Java集合框架的根接口。

  

  Collection接口的子接口:

  • java.util.List
  • java.util.Set
  • java.util.SortedSet
  • java.util.NavigableSet
  • java.util.Queue
  • java.util.concurrent.BlockingQueue
  • java.util.concurrent.TransferQueue
  • java.util.Deque
  • java.util.concurrent.BlockingDeque

  Map接口的子接口:

  • java.util.SortedMap
  • java.util.NavigableMap
  • java.util.concurrent.ConcurrentMap
  • java.util.concurrent.ConcurrentNavigableMap

 

 

  6、集合類

  標准集合類實現了Collection接口,其中一些是抽象類,實現部分接口,其它是具體類,可以直接在代碼中使用。

常見的集合類
Interface Hash Table Resizable Array Balanced Tree Linked List

Hash Table+

Linked List

Set HashSet   TreeSet   LinkedHashSet
List   ArrayList   LinkedList  
Deque   ArrayDeque   LinkedList  
Map HashMap   TreeMap   LinkedHashMap

 

  所有實現Collection接口的類都必須提供兩個標准的構造函數:

  • 無參構造函數——用於創建一個空的Collection;
  • 使用Collection類型作為參數的構造函數——用於創建一個新的Collection,目的是復制。

 

  二、泛型(Generics)

  泛型允許在定義類、接口和方法時使類型(類、接口)成為參數,聲明的類型參數在使用時用具體的類型替換。

  泛型主要應用在集合框架中。

 

  1、為什么使用泛型 

  • 提高程序的類型安全;泛型的使用讓編譯器可以驗證類型假設。
  • 有助於避免(強制)轉型,使得編譯器能夠在編譯時發現轉型錯誤而不用等到運行時
  • 可以實現通用算法

  

  2、泛型類

  泛型類的定義和聲明:

  類名之后通過<>指定一個或者多個類型參數的名字,同時還可以對類型參數的取值范圍進行限定,多個類型參數之間使用逗號分隔。

public class Matrix<T>{ …. }

  泛型的使用:

  定義完類型參數后,可以在該類幾乎任意地方(靜態塊、靜態屬性、靜態方法除外)使用類型參數。注意,父類定義的類型參數不能被子類繼承。

/*實例化泛型類*/ Matrix<Float> ft=new Matrix<Float>();

  

  3、泛型方法

  方法也可以泛型化,不管定義他們的類是不是泛型化。

  為什么要使用泛型方法而不是將類型T添加到類定義中呢?

  • 當泛型方法是靜態時,不能使用類的類型參數。
  • 當T上的類型約束對於方法是局部時,這意味着沒有在類的另一個方法簽名中使用相同類型的T的約束。泛型方法的類型參數是局部的,可以簡化封閉類型的簽名。

  聲明泛型方法:

public <T> T ifThenElse(boolean b, T first, T second) { return b? first : second; }

  泛型類是在實例化類時指明泛型的具體類型,泛型方法是在調用方法時指明泛型的具體類型。

  編譯器會允許調用下面的代碼時使用類型推理來推斷出T的類型,並用實際參數替代T:

String s=ifThenElse(b, ”a”, ”b”); Integer i=ifThenElse(b, new Integer(1), new Integer(2));

 

  4、類型限制

  有時我們需要限制類型參數的范圍。

  類型通配符(?),Matrix<?>表示任意的泛型類型。

/*表示add()可以接受任意泛型類型的參數。*/
 public void add(Matrix<?> m);

         這種情況下,add()可以接受的參數類型太寬泛了。開發人員可能希望限制參數的具體類型,例如只希望接受Number及其子類的類型的變量,而不接受Random、Locale等類型的變量。這樣就要對通配符有所限制。

         如Matrix類,使用了類型參數T,我們讓Number類作為類型上界來限制這個類型參數:

/*表示Matrix中包含的參數類型是Number及其子類*/
public class Matrix<T extends Numbers>{…}

         當引入了類型上界后,在使用類型時就可以使用類型上界類(Number)中定義的方法。

         同理我們可以使用Number類作為類型下界:

/*表示Matrix中包含的參數類型是Number及其父類*/
public class Matrix<? super Number>{…}

  

  5、類型擦除(Type Erasure)

  泛型是在編譯器這個層次實現的,在生成的字節代碼中是不包含泛型的類型信息的。

  使用泛型時加上的類型參數,會被編譯器在編譯時去掉,這個過程稱為類型擦除。也就是說,由泛型附加的類型信息對JVM來說都是不可見的。

  編譯器在編譯時盡可能地發現可能出錯的地方,但是仍然無法避免在運行時刻出現類型轉換異常的情況。

 

  類型擦除的過程:

  首先,找到用來替換類型參數的具體類。如果指定了類型參數的上界的話,則使用上界。

  然后,把代碼中的類型參數都替換成具體類型,同時去掉出現的類型聲明,即<>的內容;

   理解了類型擦除,就會明白編譯器承擔了全部的類型檢查工作。編譯器禁止某些泛型的使用方式,是為了確保類型的安全性。

 

  很多泛型的特性都與類型擦除有關,如

  • 靜態變量是被泛型類的所有實例共享的,即泛型不能用於靜態變量
  • 泛型的類型參數不能用在異常處理的catch語句中,因為異常處理是由JVM在運行時刻進行的。由於類型擦除,JVM已經無法區分源於同一泛型類型的兩個不同類型的異常。

 

  6、開發泛型類  

  因為類型擦除機制,類型參數並不能用來(在類中)創建對象(比如T t=new T();)或是靜態變量的類型。

/*泛型類*/
public class Lhist<V>{} /*創建泛型類實例*/ Lhist<Integer>li=new Lhist<Integer>(30);

 

  7、泛型的最佳實踐

  使用泛型常見的實踐原則:

  • 在代碼中避免泛型類和原始類型混用,如List<String>和List不應共同使用。
  • 使用帶通配符(?)的泛型類時,需要明確通配符所代表的一組類型的概念。
  • 不能實例化泛型類型變量,然后利用反射的newInstance來創建實例;同樣,不能創建一個泛型的數組。
  • 盡量不要忽視編譯器給出的警告。

 


免責聲明!

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



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