集合框架基礎知識-----java基礎知識
Java集合框架 :接口:Collection、List 、Set、 Map;實現類:ArrayList、LinkedList、Vector、HashSet、TreeSet、HashMap、HashTable、TreeMap
java中集合類位於java.util包下,與下面四個接口有關Collection,List,Set,Map接口。
Collection接口 |
無索引,即無get方法 |
List接口 |
元素可重復、可以存放null值、有索引 |
Set接口 |
元素不可重復,無索引 |
ArrayList實現類 |
遍歷速度快,插入數據效率低,線程不安全 |
Vector實現類 |
底層類似ArrayList、線程安全 |
LinkedList實現類 |
遍歷速度慢,插入數據效率高,線程不安全 |
HashSet實現類 |
元素無順序,可以存放null值,線程不安全,其有HashMap實現 |
TreeSet實現類 |
元素有順序,不可存放null值,線程不安全,其有TreeMap實現,元素必須實現Comparable接口或Comparator接口 |
Map接口 |
具有key和value,其key一個Set,value為一個Collection集合 |
HashMap實現類 |
無順序,線程不安全 |
HashTable實現類 |
無順序,線程安全 |
TreeMap實現類 |
有順序,線程不安全 |
一.Collection接口
Collection 層次結構 中的根接口。Collection 表示一組對象,這些對象也稱為 collection 的元素。一些 collection 允許有重復的元素,而另一些則不允許。一些 collection 是有序的,而另一些則是無序的。JDK 不提供此接口的任何直接 實現:它提供更具體的子接口(如 Set 和 List)實現。此接口通常用來傳遞 collection,並在需要最大普遍性的地方操作這些 collection。
Collection常用的方法:
boolean add(Object obj):
boolean contains(Object obj):集合中是否已經存在object對象,同時是指equals()方法比較對象返回true.
boolean remove(Object obj):從集合中移除Object對象。
void clear():清空集合。
int size():返回集合所包含的對象數目。
Object[] toArray():返回集合中全部對象的數組。
Object[] toArray(Object[] objs):把集合中的對象放入objs對象數組中,objs對象數組需要事先創建。
二.List接口
List集合代表一個元素有序,可重復的集合,集合中的每個元素都有其對應的順序索引。
常用實現類:ArrayList LinkedList
遍歷方式:for循環,Iterator
- 1. List接口方法
void add(int
index,Object e):將元素e添加到List集合中的index處;
boolean addAll(int index,Collection c):將集合c所包含的所有元素都插入在List集合的index處;
Object get(int index):返回集合index索引處的元素;
int indexOf(Object o):返回對象o在List集合中第一次出現位置的索引;
int lastIndexOf(object o):返回對象o在List集合中最後一次出現的位置索引;
Object remove(int index):刪除並返回index索引處的元素;
Object set(int index,Object e):把集合index處的元素替換為e對象,返回以前在指定位置的元素;
List subList(int fromIndex,int toIndex):返回從所有fromIndex(包括)到toIndex(不包括)處所有集合元素的子集合。
ListIterator
Iterator的子接口,專門用於操作List集合的輸出;
List自己還有一個listIterator()方法,該方法返回ListIterator對象,ListIterator繼承了Iterator接口,提供了專門操作List的方法。在Iterator上額外增加的方法:
支持雙向輸出:
boolean hasPrevious():返回該叠代器關聯集合是否還有上一個元素;
Object previous():返回該叠代器的上一個元素;
2. List接口中常用類及區別
Vector:線程安全,但速度慢,已被ArrayList替代。
ArrayList:線程不安全,查詢速度快。
LinkedList:鏈表結構,增刪速度快。
Java的List接口有3個實現類,分別是ArrayList、LinkedList、Vector,他們用於存放多個元素,維護元素的次序,而且允許元素重復。
3個具體實現類的區別如下:
1). ArrayList是最常用的List實現類,內部是通過數組實現的,它允許對元素進行快速隨機訪問。數組的缺點是每個元素之間不能有間隔,當數組大小不滿足時需要增加存儲能力,就要將已經有數組的數據復制到新的存儲空間中。當從ArrayList的中間位置插入或者刪除元素時,需要對數組進行復制、移動、代價比較高。因此,它適合隨機查找和遍歷,不適合插入和刪除,允許空元素
2). Vector與ArrayList一樣,也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。
3). LinkedList是用鏈表結構存儲數據的,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。另外,接口中沒有定義的方法get,remove,insertList,專門用於操作表頭和表尾元素,可以當作堆棧、隊列和雙向隊列使用。LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建 List時構造一個同步的List:
List
list = Collections.synchronizedList(new LinkedList(...));
查看Java源代碼,發現當數組的大小不夠的時候,需要重新建立數組,然後將元素拷貝到新的數組內,ArrayList和Vector的擴展數組的大小不同。
關於ArrayList和Vector區別如下:
- Array List在內存不夠時默認是擴展50% + 1個,Vector是默認擴展1
- Vector提供indexOf(obj, start)接口,ArrayList沒有。
- Vector屬於線程安全級別的,但是大多數情況下不使用Vector,因為線程安全需要更大的系統開銷。
3. ArrayList實現類
ArrayList 內部以數組的形式來保存集合中的元素,線程不安全;通常用for循環遍歷。Vector線程安全,但Vector是個古老的類,存在很多缺點。
方法名 |
說明 |
boolean add(Object obj) |
將元素添加到集合中 |
boolean add(int index,Object obj) |
將元素obj插入到集合的index索引位置 |
Object get(int index) |
返回集合中索引為index的元素 |
int indexOf(Object obj) |
返回元素在集合中出現的索引 |
Object set(int index,Object obj) |
將index索引位置的元素替換為obj元素 |
Object remove(int index) |
刪除並返回index索引位置的元素 |
boolean isEmpty () |
判斷集合是否為空 |
boolean contains (Object obj) |
判斷集合中是否包含obj |
示例:
- public class ArrayLsitDemo {
- /**
- * @param args
- */
- public static void main(String[] args) {
- ArrayList<String> arr = new ArrayList<String>();
- //增
- arr.add("菠蘿");
- arr.add("香蕉");
- arr.add("李子");
- print(arr);
- //刪
- arr.remove(0);//根據索引刪除,引用對象知識移除地址
- print(arr);
- //改
- arr.set(1, "橙子");
- print(arr);
- //查
- System.out.println(arr.get(0));
- }
- //遍歷
- public static void print(ArrayList<String> arr){
- for(String str:arr){
- System.out.print(str + " ");
- }
- System.out.println();
- }
- }
4. LinkedList實現類
LinkedList可以根據索引來訪問集合中的元素,此外還實現了Deque接口,所以也可以當成雙端隊列來使用,即可當“棧”(先進後出),也可以當作隊(先進先出);內部是以線性表和鏈表實現的,保證輸入的順序。通常用Iterator遍歷。
方法名 |
說明 |
void addFirst(Object o) |
將給定元素插入當前集合頭部 |
void addLast(Object o) |
將給定元素插入當前集合尾部 |
Object getFirst( ) |
獲得當前集合的第一個元素 |
Object getLast( ) |
獲得當前集合的最後一個元素 |
Object removeFirst( ) |
移除並返回當前集合的第一個元素 |
Object removeLast( ) |
移除並返回當前集合的最後一個元素 |
示例:
- public class LinkedListDemo {
- /**
- * @param args
- */
- public static void main(String[] args) {
- LinkedList<String> list = new LinkedList<String>();
- list.add("哈哈");
- list.add("呵呵");
- list.add("嘿嘿");
- print(list);
- list.addFirst("嘻嘻");//鏈表可以在頭或尾插入
- print(list);
- //將元素加入到對頭
- list.offerFirst("來來");
- //將元素加入到隊尾
- list.offerLast("去去");
- print(list);
- //訪問並不刪除棧頂
- System.out.println("訪問並不刪除棧頂----" +list.peekFirst());
- print(list);
- //訪問並刪除棧頂
- System.out.println("訪問並刪除棧頂----" + list.poll());
- print(list);
- }
- public static void print(List list){
- Iterator iterator = list.iterator();
- while(iterator.hasNext()){
- System.out.print(iterator.next() + " ");
- . }
- System.out.println();
- . }
- }
三.Set接口
List集合代表一個元素不可重復的集合。操作數據的方法與List類似,Set接口不存在get()方法
常用實現類:HashSet(無序) TreeSet(有序)
遍歷方式:for循環,Iterator
- 1. Set接口方法
l 添加元素
boolean add(E e) 如果 set 中尚未存在指定的元素,則添加此元素(可選操作)。
boolean addAll(Collection<? extends E> c) 如果 set 中沒有指定 collection 中的所有元素,則將其添加到此 set 中(可選操作)。
l 遍歷Set
Iterator<E> iterator() 返回在此 set 中的元素上進行叠代的叠代器。
l 是否為空
boolean isEmpty() 如果 set 不包含元素,則返回 true。
l 元素個數
int size() 返回 set 中的元素數(其容量)。
l 清除元素
void clear() 移除此 set 中的所有元素(可選操作)。
boolean remove(Object o) 如果 set 中存在指定的元素,則將其移除(可選操作)。
boolean removeAll(Collection<?> c) 移除 set 中那些包含在指定 collection 中的元素(可選操作)。
l 是否包含元素或集合
boolean contains(Object o) 如果 set 包含指定的元素,則返回 true。
boolean containsAll(Collection<?> c) 如果此 set 包含指定 collection 的所有元素,則返回 true。
l 其他
boolean equals(Object o) 比較指定對象與此 set 的相等性。
int hashCode() 返回 set 的哈希碼值。
Object[] toArray() 返回一個包含 set 中所有元素的數組。
<T> T[] toArray(T[] a) 返回一個包含此 set 中所有元素的數組;返回數組的運行時類型是指定數組的類型。
- 2. HashSet實現類
此類實現 Set 接口,由哈希表(實際上是一個 HashMap 實例)支持。它不保證 set 的叠代順序;特別是它不保證該順序恒久不變。此類允許使用 null 元素。
此類為基本操作提供了穩定性能,這些基本操作包括 add、remove、contains 和 size,假定哈希函數將這些元素正確地分布在桶中。對此 set 進行叠代所需的時間與 HashSet 實例的大小(元素的數量)和底層 HashMap 實例(桶的數量)的“容量”的和成比例。因此,如果叠代性能很重要,則不要將初始容量設置得太高(或將加載因子設置得太低)。
註意,此實現不是同步的。如果多個線程同時訪問一個哈希 set,而其中至少一個線程修改了該 set,那麽它必須 保持外部同步。這通常是通過對自然封裝該 set 的對象執行同步操作來完成的。如果不存在這樣的對象,則應該使用 Collections.synchronizedSet 方法來“包裝” set。最好在創建時完成這一操作,以防止對該 set 進行意外的不同步訪問:
Set s = Collections.synchronizedSet(new HashSet(...));
- 3. TreeSet實現類
基於 TreeMap 的 NavigableSet 實現。使用元素的自然順序對元素進行排序,或者根據創建 set 時提供的 Comparator 進行排序,具體取決於使用的構造方法。
註意,如果要正確實現 Set 接口,則 set 維護的順序(無論是否提供了顯式比較器)必須與 equals 一致。(關於與 equals 一致 的精確定義,請參閱 Comparable 或 Comparator。)這是因為 Set 接口是按照 equals 操作定義的,但 TreeSet 實例使用它的 compareTo(或 compare)方法對所有元素進行比較,因此從 set 的觀點來看,此方法認為相等的兩個元素就是相等的。即使 set 的順序與 equals 不一致,其行為也是 定義良好的;它只是違背了 Set 接口的常規協定。
註意,此實現不是同步的。如果多個線程同時訪問一個 TreeSet,而其中至少一個線程修改了該 set,那麽它必須 外部同步。這一般是通過對自然封裝該 set 的對象執行同步操作來完成的。如果不存在這樣的對象,則應該使用 Collections.synchronizedSortedSet 方法來“包裝”該 set。此操作最好在創建時進行,以防止對 set 的意外非同步訪問:
SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));
l TreeSet原理
/*
* TreeSet存儲對象的時候, 可以排序, 但是需要指定排序的算法
*
* Integer能排序(有默認順序), String能排序(有默認順序), 自定義的類存儲的時候出現異常(沒有順序)
*
* 如果想把自定義類的對象存入TreeSet進行排序, 那麽必須實現Comparable接口
* 在類上implement Comparable
* 重寫compareTo()方法
* 在方法內定義比較算法, 根據大小關系, 返回正數負數或零
* 在使用TreeSet存儲對象的時候, add()方法內部就會自動調用compareTo()方法進行比較, 根據比較結果使用二叉樹形式進行存儲
*/
四.Map接口
Map接口儲存一組成對的鍵-值對象,提供key(鍵)到value(值)的映射,Map中的key不要求有序,不允許重復。value同樣不要求有序,但可以重復。最常見的Map實現類是HashMap,他的儲存方式是哈希表,優點是查詢指定元素效率高。
常用實現類:HashMap(無序) TreeMap(有序)、HashTable(過時)
遍歷方式:for循環,Iterator
- 1. Map接口方法
l Map 接口的常用方法如下所示:
No. |
方法 |
類型 |
描述 |
1 |
V put(K key,V value) |
普通 |
增加內容 |
2 |
V get(Object key) |
普通 |
取得設置的內容,根據key取得 |
3 |
boolean containsKey(Object key) |
普通 |
查找指定的key 是否存在 |
4 |
boolean containsValue(Object value) |
普通 |
查找指定的value 是否存在 |
5 |
boolean isEmpty() |
普通 |
判斷集合是否為空 |
6 |
Set<K> keySet() |
普通 |
將全部的key變為Set 集合 |
7 |
Collection<V> values() |
普通 |
將全部的value 變為Collection集合 |
8 |
V remove(Object key) |
普通 |
根據key 刪除內容 |
9 |
void putAll(Map<? extends K,? extends V>m) |
普通 |
增加一組數據 |
- 2. HashMap實現類
基於哈希表的 Map 接口的實現。此實現提供所有可選的映射操作,並允許使用 null 值和 null 鍵。(除了非同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順序恒久不變。
註意,此實現不是同步的。如果多個線程同時訪問一個哈希映射,而其中至少一個線程從結構上修改了該映射,則它必須 保持外部同步。(結構上的修改是指添加或刪除一個或多個映射關系的任何操作;僅改變與實例已經包含的鍵關聯的值不是結構上的修改。)這一般通過對自然封裝該映射的對象進行同步操作來完成。如果不存在這樣的對象,則應該使用 Collections.synchronizedMap 方法來“包裝”該映射。最好在創建時完成這一操作,以防止對映射進行意外的非同步訪問,如下所示:
Map m = Collections.synchronizedMap(new HashMap(...));
- 3. TreeMap實現類
基於紅黑樹(Red-Black tree)的 NavigableMap 實現。該映射根據其鍵的自然順序進行排序,或者根據創建映射時提供的 Comparator 進行排序,具體取決於使用的構造方法。
註意,此實現不是同步的。如果多個線程同時訪問一個映射,並且其中至少一個線程從結構上修改了該映射,則其必須 外部同步。(結構上的修改是指添加或刪除一個或多個映射關系的操作;僅改變與現有鍵關聯的值不是結構上的修改。)這一般是通過對自然封裝該映射的對象執行同步操作來完成的。如果不存在這樣的對象,則應該使用 Collections.synchronizedSortedMap 方法來“包裝”該映射。最好在創建時完成這一操作,以防止對映射進行意外的不同步訪問,如下所示:
SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));
- 4. HashMap和HashTable區別
Hashtable 實際上與Vector 的產生時代是一樣,也屬於最早的集合操作類。之後只是擴展了其應用實現了Map 接口而已
HashTable類實現一個哈希表,該哈希表將鍵映射到相應的值。任何非 null 對象都可以用作鍵或值。
為了成功地在哈希表中存儲和獲取對象,用作鍵的對象必須實現 hashCode 方法和 equals 方法。
No |
區別點 |
HashMap |
Hashtable |
1 |
推出時間 |
是在JDK1.2之後推出的,屬於新的類 |
是在JDK1.0時推出的,屬於舊的操作類 |
2 |
操作 |
采用異步的處理操作 |
采用同步的處理操作 |
3 |
性能 |
性能高 |
性能相對較低 |
4 |
安全 |
非線程安全的操作 |
線程安全 |
五.Collections類
Java中給我們提供了一個工具類Collections來方便我們操作集合,在該類中的全部方法均為static靜態方法,可以直接通過類名調用。其中比較常用的方法有以下方法:
void sort(List list,Comparator com)-- >如果我想將一個List數組進行排序,需要將數組中元素取出再放入一個TreeSet集合然後再傳入一個比較器,而用這個方法直接傳入一個比較器就可以了
void max(List list,Comparator com)-- >根據比較器取出最大值
int binarySearch(List list,Object key)-- >找出List集合元素key並返回搜索鍵的索引。註意執行該方法時必須要對集合進行sort操作,否則結果是不明確的,或者在參數中再傳入一個比較器。如果沒有該元素,則返回(-(插入點)-1)。
void fill(List list,Object obj)-- >將list集合中所有元素換為obj
void replaceAll(List list,ObjectoldValue,Object newValue)-- >將集合中所有為oldValued的元素換成newValue元素。
void reverse(List list)-- >將集合翻轉
Comparator reverseOrder()-- >返回一個比較器,可以講集合內元素順序倒轉。
CollectionsynchronizedCollection(Collection collection) -- >通過傳入集合獲得一個同步的集合
List synchronizedList(List list)
Set synchronizedSet(Set set)
Map synchronizedMap(Map map)
void swap(List list,int index1,int index2)-->將集合list中角標為index1和index2的元素互換位置
六.泛型
泛型是java在jdk1.5之後才出現的。因為操作集合的時候每次都要判斷元素類型,會出現ClassCastException。所以引入了泛型機制,使元素類型在編譯的時候就做了限定。例如定義一個Collection <String> c=new Collection<String> ();那麽這個Collection集合中就只能存入String類型的對象。
參數化類型不考慮類型參數的繼承關系,比如Vector<String>v = new Vector<Object>()或者Vector<Object> v = new Vector<String>();都是錯誤的。如果想達到這個效果可以用通配符來做到。如Vector<?extends Object> v=new Vector<String>()。
使用?通配符可以引用其他各種參數化類型,?通配符定義的變量主要用作引用,可以調用與參數化無關的方法,不能調用與參數化有關的方法。如我們定義一個打印參數化集合的方法。
public void printCollection(Collection<?> collection )
{
for(Object obj:collection)
System.out.println(obj);
}
collection.size();//正確,因為此方法與類型參數沒有關系
collection.add(“abc”);//錯誤,因為collection不能確定自己匹配的參數是String
通配符的上限是?extends T;通配符的下限是? super T。
泛型是提供給Javac編譯器使用的。可以限定集合中輸入的類型,讓編譯器擋住原始程序的非法輸入,編譯器編譯帶類型說明的集合時會去掉“類型”信息,使程序運行效率不受影響,對於參數化的泛型類型,getClass()方法的返回值和原始類型完全一樣,由於編譯生成的字節碼會去掉泛型的類型信息,只要能跳過編譯器,就可以往某個泛型集合中加入其它類型的數據,例如,用反射得到集合,再調用其add方法即可。
void sort(List list,Comparator com)-- >如果我想將一個List數組進行排序,需要將數組中元素取出再放入一個TreeSet集合然後再傳入一個比較器,而用這個方法直接傳入一個比較器就可以了
void max(List list,Comparator com)-- >根據比較器取出最大值
需要註意的幾點是泛型的實際參數只能是引用類型不可以是基本類型,泛型定義在類上時。類中的靜態成員不具備該類型參數。
集合框架基礎知識-----java基礎知識