不知你是否還記得高中咱們學過的集合,映射,函數,數學確實很牛逼,拿它來研究java集合類,垂手可得的就把知識理解了。本篇文章適合初學java集合類的小白,也適合補充知識漏缺的學習者,同時也是面試者能夠參考的一份資料。java
回顧一下以前所學的知識,結合我多年的高中數學教學經驗,相信你會對某些知識有一些新的感悟。node
集合:通常地,咱們把研究對象統稱爲元素(element),把一些元素組成的整體叫作集合(set)。面試
對於一個給定的集合,其具備的特徵:數組
肯定性:集合中的元素都是肯定的。微信
互異性:集合中的元素都是不一樣的。數據結構
無序性:集合中的元素的順序是無序的。多線程
映射:通常地,咱們有:app
設A,B是兩個非空的集合,若是按照某一個肯定的對應關係f.是對應集合A中的任意一個元素x,在集合B中都有惟一肯定的元素y與之對應,那麼就稱對應f:A—>B爲集合A到集合B的一個映射(mapping)。框架
其實簡單的來說,何謂映射,就是函數上將的關係對應,例如:ide
函數 f(x)=x^2 那麼每個x都有惟一的y與之對應,這就是映射關係的一個模型。
而方程 x^2+y^2=1,這個很明顯是圓心爲(0,0)的半徑爲1的圓,任取一個x可能會有一個或者兩個y與之對應,這就不能稱爲映射,進而不能稱爲函數。(1,0)或者(-1,0)這時候的x只有惟一的肯定的y和它對應。
集合類產生的緣由:在通常的狀況下,咱們在寫程序時並不知道將須要多少個對象,或者是否須要更加複雜的方式存儲對象,顯然使用具備固定長度的數組已經不能解決這個問題了。因此java 實用類庫提供了一套至關完整的容器類來解決這個問題。
java容器類類庫的用途是「保存對象」,可將其劃分爲兩個不一樣的概念:
1)collection.獨立元素的序列。主要包含List(序列),Set(集合),Queue(隊列)
List:按照插入的順序保存元素;
Set:不能有重複的元素;
Queue:按照排隊規則來肯定對象產生的順序(一般與它們被插入的順序相同);
2)Map:一組成對的「鍵值對」對象,容許咱們使用鍵來查找值。
針對常用的類庫,咱們只列出List,Set,Map之間的繼承關係:
List接口在Collection的基礎上添加了大量的方法,使得能夠在List的中間插入和刪除元素。
繼承自List的子類有ArrayList, LinkedList ,Vector三類。
list的特徵:
1 有序的Collection 2 容許重複的元素,容許空的元素。 3 插入相似的數據:{1,2,4,{5,2},1,3};
其主要用於查找,對於刪除和插入,耗時巨大。ArrayList是以數組實現的列表,不支持同步。
優勢:利用索引位置能夠快速的定位訪問
適合變更不大,主要用於查詢的數據
和java的數組相比較,其容量是能夠動態調整的。
缺點:不適合指定位置的插入,刪除操做。
--ArrayList在元素填滿容器是會自動擴充容器大小的50%
ArrayListTest 代碼分析:
add()方法,添加元素,默認是在後面添加。
add(index,value),在指定索引處添加元素。會進行元素的移動。源碼以下:
1 public void add(int index, E element) { 2 rangeCheckForAdd(index); 3 ensureCapacityInternal(size + 1); // Increments modCount!! 4 System.arraycopy(elementData, index, elementData, index + 1, 5 size - index); 6 elementData[index] = element; 7 size++; 8 }
remove(index)刪除指定位置上的元素。源碼以下:
1 public E remove(int index) { 2 rangeCheck(index); 3 modCount++; 4 E oldValue = elementData(index); 5 int numMoved = size - index - 1; 6 if (numMoved > 0) 7 System.arraycopy(elementData, index+1, elementData, index, 8 numMoved); 9 elementData[--size] = null; // clear to let GC do its work 10 return oldValue; 11 }
從源碼能夠分析出,在ArrayList進行插入和刪除的時候,會進行相似順序表的操做,移動元素,空出位置,而後插入元素。刪除:依次移動後面的元素覆蓋指定位置的元素。這就會大大減慢ArrayList插入和刪除的效率。
舉一個應用的例子,更好的理解ArrayList:
1 public class ArrayListTest { 2 public static void main(String[] args) { 3 //泛型的用法,只容許Integer類型的元素插入。 4 ArrayList<Integer> arrayList =new ArrayList<Integer>(); 5 //增長元素 6 arrayList.add(2); 7 arrayList.add(3); 8 arrayList.add(4); 9 arrayList.add(5); 10 arrayList.add(4); 11 arrayList.add(null);//ArrayList容許空值插入, 12 arrayList.add(new Integer(3)); 13 System.out.println(arrayList);// [2, 3, 4, 5, 4, null, 3] 14 //查看元素的個數 15 System.out.println(arrayList.size());// 7 16 arrayList.remove(0); 17 System.out.println(arrayList);// [3, 4, 5, 4, null, 3] 18 arrayList.add(1, new Integer(9)); 19 System.out.println(arrayList);// [3, 9, 4, 5, 4, null, 3] 20 System.out.println("-----------遍歷方法-------"); 21 ArrayList<Integer> as=new ArrayList<Integer>(100000); 22 for(int i=0;i<100000;i++){ 23 as.add(i); 24 } 25 traverseByIterator(as); 26 traverseByFor(as); 27 traverseByForEach(as); 28 } 29 public static void traverseByIterator(ArrayList<Integer>al){ 30 System.out.println("---------迭代器遍歷-------------"); 31 long startTime=System.nanoTime();//開始時間 32 Iterator it=al.iterator(); 33 while(it.hasNext()){// 34 it.next(); 35 } 36 long endTime=System.nanoTime();//結束時間 37 System.out.println((endTime-startTime)+"納秒"); 38 } 39 public static void traverseByFor(ArrayList<Integer>al){ 40 System.out.println("---------索引遍歷-------------"); 41 long startTime=System.nanoTime();//開始時間 42 for(int i=0;i<al.size();i++) al.get(i); 43 long endTime=System.nanoTime();//結束時間 44 System.out.println((endTime-startTime)+"納秒"); 45 } 46 public static void traverseByForEach(ArrayList<Integer>al){ 47 System.out.println("---------Foreach遍歷-------------"); 48 long startTime=System.nanoTime();//開始時間 49 for(Integer temp:al); 50 long endTime=System.nanoTime();//結束時間 51 System.out.println((endTime-startTime)+"納秒"); 52 } 53 } 54 -----------遍歷方法------- 55 ---------迭代器遍歷------------- 56 10407039納秒 57 ---------索引遍歷------------- 58 7094470納秒 59 ---------Foreach遍歷------------- 60 9063813納秒 61 能夠看到利用索引遍歷,相對來講是快一些。
1 hasNext() 判斷是否有下一個元素 2 next() 獲取下一個元素 3 remove () 刪除某個元素
LinkedList:(主要用於增長和修改!)
--以雙向鏈表實現的列表,不支持同步。
--能夠被當作堆棧、隊列和雙端隊列進行操做
--順序訪問高效,隨機訪問較差,中間插入和刪除高效
--適合常常變化的數據
addFirst()在頭部添加元素
add(3,10);將10插入到第四個位置上
remove(3)刪除第四個位置的元素
代碼詳解:
1 public class LinkedListTest { 2 public static void main(String[] args) { 3 LinkedList<Integer> linkedList=new LinkedList<Integer>(); 4 linkedList.add(2); 5 linkedList.add(3); 6 linkedList.add(9); 7 linkedList.add(6); 8 linkedList.add(7); 9 System.out.println(linkedList); 10 //linkedList.addFirst(1); 11 //linkedList.addLast(10); 12 //System.out.println(linkedList); 13 linkedList.add(3, 4); 14 System.out.println(linkedList); 15 System.out.println(linkedList.get(4)); 16 LinkedList<Integer> as=new LinkedList<Integer>(); 17 for(int i=0;i<100000;i++){ 18 as.add(i); 19 } 20 traverseByIterator(as); 21 traverseByFor(as); 22 traverseByForEach(as); 23 } 24 public static void traverseByIterator(LinkedList<Integer>al){ 25 System.out.println("---------迭代器遍歷-------------"); 26 long startTime=System.nanoTime();//開始時間 27 Iterator it=al.iterator(); 28 while(it.hasNext()){ 29 it.next(); 30 } 31 long endTime=System.nanoTime();//結束時間 32 System.out.println((endTime-startTime)+"納秒"); 33 } 34 public static void traverseByFor(LinkedList<Integer>al){ 35 System.out.println("---------索引遍歷-------------"); 36 long startTime=System.nanoTime();//開始時間 37 for(int i=0;i<al.size();i++) al.get(i); 38 long endTime=System.nanoTime();//結束時間 39 System.out.println((endTime-startTime)+"納秒"); 40 } 41 public static void traverseByForEach(LinkedList<Integer>al){ 42 System.out.println("---------Foreach遍歷-------------"); 43 long startTime=System.nanoTime();//開始時間 44 for(Integer temp:al); 45 long endTime=System.nanoTime();//結束時間 46 System.out.println((endTime-startTime)+"納秒"); 47 } 48 } 49 ---------迭代器遍歷------------- 50 6562423納秒 51 ---------索引遍歷------------- 52 4565606240納秒 53 ---------Foreach遍歷------------- 54 4594622納秒 55 能夠看出使用索引遍歷,對於linkedList真的很費時間!
1 void linkBefore(E e, Node<E> succ) { 2 // assert succ != null; 3 final Node<E> pred = succ.prev; 4 final Node<E> newNode = new Node<>(pred, e, succ); 5 succ.prev = newNode; 6 if (pred == null) 7 first = newNode; 8 else 9 pred.next = newNode; 10 size++; 11 modCount++; 12 }
1 E unlink(Node<E> x) { 2 // assert x != null; 3 final E element = x.item; 4 final Node<E> next = x.next; 5 final Node<E> prev = x.prev; 6 7 if (prev == null) { 8 first = next; 9 } else { 10 prev.next = next; 11 x.prev = null; 12 } 13 14 if (next == null) { 15 last = prev; 16 } else { 17 next.prev = prev; 18 x.next = null; 19 } 20 21 x.item = null; 22 size--; 23 modCount++; 24 return element; 25 }
1 Node<E> node(int index) { 2 // assert isElementIndex(index); 3 4 if (index < (size >> 1)) { 5 Node<E> x = first; 6 for (int i = 0; i < index; i++) 7 x = x.next; 8 return x; 9 } else { 10 Node<E> x = last; 11 for (int i = size - 1; i > index; i--) 12 x = x.prev; 13 return x; 14 } 15 }
-和ArrayList相似,可變數組實現的列表
-Vector同步,適合在多線程下使用
-原先不屬於JCF框架,屬於java最先的數據結構,性能較差
-從JDK1.2開始,Vector被重寫,並歸入JCF中
-官方文檔建議在非同步的狀況下,優先採用ArrayList
其實vector相似於ArrayList,因此在通常狀況下,咱們能優先使用ArrayList,在同步的狀況下,是能夠考慮使用Vector
代碼例子:
1 public class VectorTest { 2 public static void main(String[] args) { 3 Vector<Integer> vs=new Vector<Integer>(); 4 vs.add(1); 5 vs.add(4); 6 vs.add(3); 7 vs.add(5); 8 vs.add(2); 9 vs.add(6); 10 vs.add(9); 11 System.out.println(vs); 12 System.out.println(vs.get(0)); 13 vs.remove(5); 14 System.out.println(vs); 15 /*Integer []a=new Integer[vs.size()]; 16 vs.toArray(a); 17 for(Integer m:a){ 18 System.out.print(m+" "); 19 }*/ 20 Vector <Integer> as=new Vector <Integer>(100000); 21 for(int i=0;i<1000000;i++){ 22 as.add(i); 23 } 24 traverseByIterator(as); 25 traverseByFor(as); 26 traverseByForEach(as); 27 traverseEm(as); 28 } 29 public static void traverseByIterator(Vector<Integer>al){ 30 System.out.println("---------迭代器遍歷-------------"); 31 long startTime=System.nanoTime();//開始時間 32 Iterator it=al.iterator(); 33 while(it.hasNext()){ 34 it.next(); 35 } 36 long endTime=System.nanoTime();//結束時間 37 System.out.println((endTime-startTime)+"納秒"); 38 } 39 public static void traverseByFor(Vector<Integer>al){ 40 System.out.println("---------索引遍歷-------------"); 41 long startTime=System.nanoTime();//開始時間 42 for(int i=0;i<al.size();i++) al.get(i); 43 long endTime=System.nanoTime();//結束時間 44 System.out.println((endTime-startTime)+"納秒"); 45 } 46 public static void traverseByForEach(Vector<Integer>al){ 47 System.out.println("---------Foreach遍歷-------------"); 48 long startTime=System.nanoTime();//開始時間 49 for(Integer temp:al){ 50 temp.intValue(); 51 } 52 long endTime=System.nanoTime();//結束時間 53 System.out.println((endTime-startTime)+"納秒"); 54 } 55 public static void traverseEm(Vector<Integer>al){ 56 System.out.println("---------Enumeration遍歷-------------"); 57 long startTime=System.nanoTime();//開始時間 58 for(Enumeration <Integer> ei=al.elements();ei.hasMoreElements();){ 59 ei.nextElement(); 60 } 61 long endTime=System.nanoTime();//結束時間 62 System.out.println((endTime-startTime)+"納秒"); 63 } 64 } 65 ---------迭代器遍歷------------- 66 28927404納秒 67 ---------索引遍歷------------- 68 32122768納秒 69 ---------Foreach遍歷------------- 70 25191768納秒 71 ---------Enumeration遍歷------------- 72 26901515納秒 73 能夠看到Foreach遍歷要快於其餘的遍歷方法。
1 public synchronized void insertElementAt(E obj, int index) { 2 modCount++; 3 if (index > elementCount) { 4 throw new ArrayIndexOutOfBoundsException(index 5 + " > " + elementCount); 6 } 7 ensureCapacityHelper(elementCount + 1); 8 System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); 9 elementData[index] = obj; 10 elementCount++; 11 }
1 public synchronized E get(int index) { 2 if (index >= elementCount) 3 throw new ArrayIndexOutOfBoundsException(index); 4 5 return elementData(index); 6 } 7 E elementData(int index) { 8 return (E) elementData[index]; 9 }
其實List這部份內容用的數學知識不是不少,可是set和Map確實是相似於數學模型的概念。期待後續Set,Map的學習。
我的微信公衆號