thinking in java 第6天

第十一章:持有對象(容器類源碼非常清楚也很強大,像我們這種菜鳥應該多學習)

  1. 泛型和集合類型安全
    • 向上轉型可以適用
  2. 容器類:
    • Collection:一個獨立元素的序列,這些元素都服從一條或者多條規則
      • list:按照插入的順序保存元素,不關心是否重複
      • set:不能有重複元素
      • Queue:按照隊列規則來確定對象產生的順序
    • Map:鍵值對
  3. Arrays.asList():將一個數組當作list,但是底層然是以數組來實現的,所以當對這個List做增刪操作時有可能引起改變數組大小
  4. 顯示類型參數聲明:List<T> t = Arrays.<T>asList();底層返回的是一個內部類ArrayList
  5. 容器的打印:
    • Collection打印出來的是方括號括住,每個逗號分隔的
    • Map則用大括號,鍵與值則是用等號聯繫
    • ArrayList和LinkedList都是List類型,都是按照被插入的順序保存元素
    • HashSet,TreeSet,LinkedHashSet都是Set類型,是去重複的
      • hashSet的存儲順序非常複雜,待後面說
      • TreeSet:按照比較結果的升序存儲對象
      • LinkedHashSet:按照添加的順序保存對象
    • HashMap,TreeMap,LinkedHashMap,存儲的順序和上面一致,其實Set底層就是基於Map來實現的,後面會細說
  6. List:將元素維護在特定的序列中,在Collection的接口上添加了大量方法
    • ArrayList:易於隨機訪問,畢竟是依賴數組實現的
      • subList():這個函數所產生的列表的幕後就是初始列表,所以對返回的列表的操作會反映到初始列表中
      • 像remove(),retainAll()[表示取交集]等函數背後比對使用的都是equals函數,要注意這個函數比對的是引用,除非覆寫,比如String類中
    • LinkedList:易於插入刪除,是依賴鏈表實現的,這個類中多了很多函數,是爲了實現棧和隊列提供基礎的
      • 雙向鏈表實現
      • 是無頭節點的雙向鏈表
      • Queue實在LinkedList基礎之上添加了element()/offer()/peek()/poll()/remove()等方法實現的
      • element()/getFirst()/peek()都是取第一個對象,但是前兩者在list爲空時拋出NoSuchElementException異常,peek則返回null
      • remove/removeFirst/pull()和上面類似,不過都是取移除並返回頭
      • add/addFirst()/addLast()
  7. 迭代器
    • Iterator:單向的
      • 使用方法iterator()要求容器返回一個Iterator,Iterator將準備好返回序列的第一個元素
      • 使用next()獲得序列的下一個元素
      • 使用hasNext()檢查序列中是否有元素
      • 使用remove將迭代器新近返回的元素刪除(一般要先調用next(),保證有新近返回的元素,因爲根據源碼知道,remove裏刪除的index是在next()方法裏設置的)
    • ListIterator:只能用於List類的訪問,而且是雙向的
      • 可以通過調用listIterator()方法產生一個指向List開始處的ListIterator,並且還可以通過調用listIterator(n)創建一個一開始就指向列表索引爲n的元素的ListIterator
      • 通過源代碼知道ListIterator是對Iterator的一次擴展,增加了實現雙向移動的一些函數
    • 依賴LinkedList實現棧,類名後面的<T>告訴編譯器這將是一個參數化類型
    • import java.util.LinkedList;
      
      public class StackByLinkedList<T> {
      	private LinkedList<T> storage =  new LinkedList<T>();
      	public void push(T v){ storage.push(v); }
      	public T peek(){ return storage.peek(); }
      	public T pop(){ return storage.pop(); }
      	public boolean empty(){ return storage.isEmpty(); }
      	public String toString(){ return storage.toString(); }
      }
    • 當然在util包中實現了Stack這個類,不過是繼承了Vector,依賴數組實現的
  8. Set:之前說過Set是依賴Map的key來實現的,可以看源碼
    • 不保存重複的元素,一般利用這個特性來測試歸屬行
    • Set和Collection完全一樣的接口,沒有任何額外的功能
    • HashSet/TreeSet/LinkedHashSet
      • TreeSet依賴紅黑樹,結果是排序的
      • HashSet依賴散列函數
      • LinkedHashSet也使用了散列函數,但是使用了鏈表來維護元素的插入順序
  9. Map:鍵值對,可以用於組合別的數據結構,如Map<A,List<? extends B>>();
  10. Queue:典型的FIFO
    • LinkedLIst提供了方法支持隊列的行爲,而且實現了Queue的接口
    • offer():將一個元素插入到隊尾
    • peek/element都是在不移除的情況下返回對頭
    • poll/remove都是在移除的情況下返回對頭
    • PriorityQueue
      • 一般情況下會維持一個堆,在offer()插入時會根據一定的規則排序,可以通過Comparator來修改排序規則
      • 一般情況下重複是允許的,而且最小的值擁有最高的優先級
  11. Collection與iterator
  12. Foreach與迭代器
    • foreach適用於所有Collection
    • 所有實現了Iterable的接口都可以用foreach實現移動
    • public class IterableClass implements Iterable<String>{
      	private String[] words = {"s0","s1","s2","s3","s4"};
      	
      	public Iterator<String> iterator(){
      		return new Iterator<String>() {
      			private int index = 0;
      			public String next(){
      				return words[index++];
      			}
      			public boolean hasNext(){
      				return index < words.length;
      			}
      			public void remove(){
      				
      			}
      		};
      	}
      	
      	@Test
      	public void test(){
      		for(String s : new IterableClass()){
      			System.out.println(s+" ");
      		}
      	}
      	
      }
      


    • 所有的Collection(除了Map)都實現了Iterable接口,map可以使用Entry來構建成Set集合
    • import java.util.Map;
      
      import org.junit.Test;
      
      public class EnviromentVariables {
      	@Test
      	public void test(){
      //		System.getenv()
      		for(Map.Entry entry : System.getenv().entrySet()){
      			System.out.println(entry.getKey()+" : "+entry.getValue());
      		}
      	}
      }
    • 不存在任何數組到Iterable的自動轉換,必須手工轉換
    • Arrays.asList()產生的List對象會使用底層數組作爲其物理實現,所以修改這個返回的List會修改底層的數組,如果不希望修改,則需要創建一個副本,如用new ArrayList<>包裝一下創建一個引用副本

容器圖


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章