Java基礎總結十七(集合2)
List介面
1.1 介面特點及主要子類
單列集合
可存放重複元素
元素有序
主要子類
ArrayList:底層資料結構是陣列結構。執行緒不安全的。所以ArrayList的出現替代了Vector。增刪慢,查詢快。
LinkedList:底層是連結串列資料結構。執行緒不安全的,同時對元素的增刪操作效率很高。
Vector:底層資料結構是陣列結構。jdk1.0版本。執行緒安全的。無論增刪還是查詢都非常慢,已被ArrayList替代。
1.2 List介面常用方法
void add(int index, E element) //指定索引新增元素
E remove(int index) //移除指定索引處元素
E get(int index) //獲取指定索引元素
E set(int index, E element) //修改指定索引元素
List<E> subList(int fromIndex, int toIndex)//擷取指定索引子集
int indexOf(Object o) //返回指定元素索引位置
ListIterator<E> listIterator() 注意:用於應對併發修改異常的返回迭代器方法與迭代器
1.1 具體子類介紹
1.1.1 ArrayList
ArrayList底層資料結構是陣列結構。執行緒不安全的,所以執行速度快,ArrayList的出現替代了Vector。增刪慢,查詢快,由於日常開發中使用最多的功能為查詢資料,遍歷資料,所以ArrayList是最常用的集合。目前市面上許多程式設計師開發時並不嚴謹,非常隨意地使用ArrayList完成任何需求,這種用法是不提倡的。
1.1.2 LinkedList
LinkedList與ArrayList不同,LinkedList是方便新增刪除的List。實際開發中對一個集合元素的新增與刪除經常涉及到首尾操作,索引該具體子類的特點在於提供了大量首尾操作。
public void addFirst(E e) 新增首個元素
public void addLast(E e) 新增最後元素
public E getFirst() 獲取首個元素
public E getLast() 獲取最後元素
以及其替代方法
1.1.3 Vector
Vector:我們可以將其理解為版本舊的、安全的、效率低的ArrayList,Vector中提供了一個獨特的取出方式,就是列舉Enumeration。此介面Enumeration的功能與 Iterator 介面的功能是類似的。
有興趣的可以自己瞭解:
public E elementAt(int index)
public E firstElement()
public E lastElement()
public void setElementAt(E obj, int index)
public void removeElementAt(int index)及其他刪除
public Enumeration<E> elements()
Set介面
2.1 介面特點及主要子類
Set是不包含重複元素的集合介面,其子類均無法存放相同元素。
最常用的子類是無序不可重複的HashSet。其方法與Set介面方法相同。
HashSet下還有子類LinkedHashSet,可預測迭代順序的Set集合。
2.2 判斷元素唯一原理
2.2.1 ArrayList的contains方法判斷元素是否重複原理
ArrayList的contains方法會使用呼叫方法時,傳入的元素的equals方法依次與集合中的舊元素所比較,從而根據返回的布林值判斷是否有重複元素。此時,當ArrayList存放自定義型別時,由於自定義型別在未重寫equals方法前,判斷是否重複的依據是地址值,所以如果想根據內容判斷是否重複,需要重寫equals方法。
2.2.2 HashSet的add/contains等方法判斷元素是否重複原理
Set集合不能存放重複元素,其新增方法在新增時會判斷是否有重複元素,有重複不新增,沒重複則新增。
HashSet集合由於是無序的,其判斷唯一的依據是元素型別的hashCode與equals方法的返回結果。規則如下:
先判斷新元素與集合內已經有的舊元素的HashCode值
如果不同,判斷元素不同。
如果相同,再判斷equals比較結果,返回true則相同,返回false則仍然不同。
所以,使用HashSet儲存自定義型別,如果沒有重寫該類的hashCode與equals方法,則判斷重複時,使用的地址值,如果想通過內容比較元素是否相同,需要重寫該類的hashcode與equals方法。
hashCode方法重寫規則:將該物件的各個屬性值hashCode相加即是整個物件的HashCode值。如果是基本型別,類似int,則直接返回int值就是該屬性的hash值,如果是引用型別,類似String,就呼叫該成員變數的hashCode方法返回該成員變數hash值。這樣可以根據物件的內容返回hashCode值,從而可以根據hashCode判斷元素是否唯一。
但是由於在一些”碰巧的”情況下,可能出現內容不同但hashCode相同的情況,為了避免這些情況,我們加入一些干擾係數。
可是加入干擾係數後,仍會出現一些”碰巧”的情況,所以我們還要進行equals的二次判斷。
泛型
3.1 泛型概述
我們在集合中大量使用到了泛型,這裡來完整地介紹泛型知識。
泛型用來靈活地將資料型別應用到不同的類、方法、介面當中。將資料型別作為引數傳遞。
泛型是資料型別的一部分,我們將類名與泛型合併一起看做資料型別。
泛型的定義:定義泛型類可以預支地使用未知的型別。
泛型的使用:一般在建立物件時,將未知的型別確定具體的型別。當沒有指定泛型時,預設型別為Object型別。
3.2 泛型程式碼實現
泛型類:
定義:類名後<變數> 如:class A<E> {使用E完全類的定義}
使用:建立物件時確定型別
泛型方法:
定義:方法返回值前<變數> 如:public <T> void method(){使用T}
使用:呼叫方法時確定型別
泛型介面:
定義:介面後<變數> 如: interface B<T>{使用T完成介面定義}
使用:
1、定義類時確定型別
2、始終不確定型別,直到建立物件時確定型別
3.3 泛型優點及其他
3.3.1 泛型其他
在JDK1.5出現前,使用Object代表任意型別,但在使用時,涉及到了強轉的麻煩。泛型替代了Object來代表任意型別。
泛型在編譯時會擦除:泛型僅用來在編譯期限制、方便程式設計師的操作,實際上真正編譯後的.class中是沒有泛型的,其中仍然使用的為Obejct類,通過類似多型的方式完成任意某個型別的指定。
泛型萬用字元?
定義:(檢視ArrayList的構造方法)無法在類中使用
使用:呼叫方法時可以給予任意型別。參照Arraylist的構造方法
? extends E代表只要是E型別的子類即可
? super E代表只要是E型別的父類即可
3.3.2 泛型優點
提高程式的安全性
將執行期問題轉移到了編譯期
省去了型別強轉的麻煩
優化了程式設計