? ? ? ?Java集合在某種程度上可以說是對一些數據結構與算法的封裝,并給出相應的接口,這充分的體現了面向對象編程的思想。
Java中集合的結構大概如下圖所示:
1.Iterable和Iterator
java.lang.Iterable
java.util.Iterator
? ? ? ?通過它們兩在java中的位置可以看錯Iterable是屬于基礎類的一份子,而Iterator是在集合類當中。Iterator是迭代器類,而Iterable是接口,因為Iterable中封裝了Iterator接口,只要實現了Iterable接口的類,就可以使用Iterator迭代器了。因此List和Set位于Iterable下就不難理解了。
2.List
? ? ? ? List中用的最多的為ArrayList和LinkedList,這兩個相當于數組和鏈表的形式,ArrayList是連續存儲,LinkList是分散存儲,我們可以自己動手寫來模擬這種存儲方式,而他們的優缺點也和數組鏈表的優缺點大致相同,不再陳述。
? ? ? MyArrayList,MyLinkedList
? ? ? 而Java作為面向對象語音,也為我們封裝了很多方法,以便于對List進行操作:
? ? ? int size() :獲得數據個數
? ? ? boolean contains(Object o) :是否包含數據o
? ? ? int indexOf(Object o) :返回元素o第一次出現的位置
? ? ? Object[] toArray(): 轉換成長度固定的數組
? ? ? get(int index) :返回第index個元素
? ? ? add(E e):向最后添加元素。數據可以重復
? ? ? add(int index, E element):某個位置之后添加元素
? ? ? remove(int index):刪除一個位置的元素
? ? ? remove(Object o):刪除元素o
? ? ? void clear():清空
3.Set
? ? ? ?Set,類似于數學中的集合,他存儲的元素是不重復的,Set中的數據都是只有一份,并且Set中的數據不是以鍵值對存儲的,以下是Set中一些常用的方法:
? ? ? boolean contains(Object o):判斷是否存在元素o
? ? ? add(E e) :添加元素到集合
? ? ? remove(Object o) :從集合移除
? ? ? int size() :獲取個數
? ? ? boolean isEmpty():是否空
? ? ? void clear() :清空
4.Map
? ? ? ?首先實現了Map接口的類的數據的存儲都是以鍵值對的形式來進行存儲的,而在實際中用的最多的就是HashMap,要了解什么是HashMap,要先了解什么是哈希算法。簡單來說,哈希算法就是根據一定的規則,計算一個數據應該放到哪個地址,因此,就有一定的幾率使得兩個完全不同的數據計算得到的地址是一樣的,而一個好的哈希算法是使這種情況發生的幾率最小。
? ? ? HashMap中數據進行存儲時鍵不能重復,但值可以重復,這就造成了數據的存儲略慢,但是查詢速度快,理論上來講查詢速度和數據量無關。正所謂魚與熊掌不可兼得,編程也是這樣的,同樣只要了解其基本原理,在某種程度上就可以說已經學會了HashMap,這得力于Java中封裝的大量方法:
? ? ? int size() :鍵值對條數
? ? ? V get(Object key) :根據鍵獲得值。如果不存在這樣的鍵則返回null
? ? ? boolean containsKey(Object key) :判斷鍵是否存在
? ? ? put(K key, V value) :鍵值對放入map。如果已經key已經存在則用新的鍵值對替換舊的鍵值對,也就是“鍵不能重復”
? ? ? remove(Object key):根據鍵移除鍵值對
? ? ? void clear() :清空
? ? ? Set keySet() :得到所有的key,返回值是Set類型。
5.泛型
? ? ? ?泛型,簡單來講,就是人為規定了參數的標準,或者類型,除了我規定的類型外都不可以傳進來,Java中除了集合可以使用外我們也可以自己定義泛型,方法也很簡單:在類名后面用<>聲明類型的“代替符號”,然后類中需要用這個類型的地方用這個名字就行。
? ? ? 泛型不能使用int、double、boolean等原始類型,而應使用比如Integer、Double、Boolean等包裝類型,怎樣去判斷一個類型是基本類型還是包裝類型呢:首字母大寫是包裝類型,小寫為基本類型。這也解釋了Java中String為什么有那么多的方法,因為“他的首字母是大寫的”。當然用的時候是可以使用原始類型,因為有拆箱裝箱。
? ? ? Java數組支持協變,什么是協變呢,簡單說就是父類相關的變量可以指向子類相關的對象,但泛型是不支持協變。
? ? ? ArrayList list1 = new ArrayList<String>() 這樣定義是沒錯的,但list1變量是不支持泛型的,而且放進去其他類型編譯時、運行時也不報錯,為什么這樣:因為有泛型擦除。
ArrayList list1 = new ArrayList<String>() ;
ArrayList<String> list2 = new ArrayList();
ArrayList list3 <String>= new ArrayList<String>();
? ? ? 泛型擦除是java文件編譯為class文件是做的鬼,如果將class文件反編譯為java文件,那么,上面三條語句會變成這樣:
ArrayList list1 = new ArrayList() ;
ArrayList<String> list2 = new ArrayList();
ArrayList list3<String> = new ArrayList();
? ? ? 正向編譯時,會自動去除后面的<String>,因此第一中實例化沒有實習泛型,第二三中實現了泛型,為了保證良好的習慣,應采取第三種書寫方式。
? ? ? 用泛型集合編寫代碼的時候可以避免放入數據類型錯誤,并且取數據的時候避免類型轉換。當然,泛型也有不好的地方:
? ? ? 1、運行時無法得知對象的泛型類型信息。比如無法用arr instanceof LinkedList判斷
? ? ? 2、一旦轉換為非泛型變量,那么就有放入非法數據的可能性。沒有根除的辦法。
? ? ? 3、不同類型的泛型不能構成重載方法。例如:
static void m1(LinkedList<Integer> list)
static void m1(LinkedList<String> list)
static void m1(LinkedList list)
? ? ? 上面三種方法是不能構成重載方法的。
5-1.有界類型
有界類型是指,在指定一個類型參數時,可以指定一個上界,聲明所有的實際類型都必須是這個超類的直接或間接子類,比如:
class className<T extends superclass>
6.其它總結
? ? ? Stack(棧):先入后出。push放入數據,pop取出數據
? ? ? Queue(隊列):先入先出。offer入隊,poll出隊
? ? ? Vector、Hashtable被廢棄,不推薦使用。