集合從概念上來看就是一堆元素放在一塊兒,咱們其實可使用數組來處理這樣的狀況(操做一堆數據),可是數組存在各類各樣的限制,使用起來並不方便,所以才推出更強大的集合處理方式,即集合框架html
數組的問題:java
容器最基本的功能就是存儲數據,取出數據,可是由於實際需求不一樣,好比是否有序,是否可重複,不一樣的數據結構,不一樣的存取效率等等緣由,系統提供了一衆不一樣特性的容器類,共同構成了集合框架算法
框架體系結構:api
其中Collection接口支持(單個形式)數據的存儲,而Map接口支持對鍵值對形式的數據的存儲數組
ps: 因爲其內部使用數組,而數組容量是固定的,這就致使了,添加刪除時都會引起數組的重建,以及數據的拷貝,數據結構
舉個例子:火焰山終於下雨了,剛開始覺得只下一點點,因此找了一個杯子裝,後來發現裝不下了,要換一個盆(建立更大的數組),那麼須要先把杯子裏的水倒進盆裏(數據拷貝)併發
適用於:讀取,查詢操做更頻繁的場景框架
ps:因爲使用的鏈表結構,因此添加刪除時僅須要在任意內存保存數據而後將指針添加到上一個數據的結尾便可,因此這添加刪除數據時比使用數組的ArrayList快不少 ,可是當須要查找數據時,就須要頻繁的移動指針(地址不是連續的),形成了查詢速度慢,ide
舉個例子: 你是要找王老闆作生意,可是你本身不認識他,因而你就找了劉老闆,劉老闆也不認識他,因而劉老闆找了李老闆,還好最後李老闆認識王老闆,找到了你要找的人,期間不能跨越中間的必須一個一個找下去學習
適用於:添加,刪除操做更頻繁的建立
能夠說HashSet就是對HashMap進行了簡單的包裝:
真正存儲數據的容器:
包裝後的添加數據的方法:
iterable叫作可迭代對象
咱們知道集合框架提供了不少不一樣的容器實現類,可是每種容器的內部實現不一樣,致使咱們須要記憶不一樣的取值方法,這對於使用者來講無疑增長學習成本,因此Java統一了各類容器的取值方式,即經過iterable接口
public Iterator iterator();//用於返回一個迭代器接口對象
Iterator叫作迭代器
迭代器用於獲取容器中的值
public boolean hasNext(); //判斷是否還有下一個 public Integer next();//獲取下一個的值
使用案例:
//寫一個支持foreach語法的類 import java.util.Iterator; public class MyTest implements Iterable<Integer> { private int num = 0; @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { @Override public boolean hasNext() { return num < 11; } @Override public Integer next() { return num++; } }; } //測試: public static void main(String[] args) { for (Integer i:new MyTest()) { System.out.println(i); } } } //該類能夠迭代獲得0-10這11個數字
ps:collection接口繼承了iterable,因此全部collection的子類能夠被foreach遍歷
咱們可使用foreach來遍歷collection的任何子類對象:
案例:
HashSet<String> set = new HashSet<String>(); set.add("1"); set.add("2"); set.add("3"); ArrayList<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String s: list) { System.out.println(s); } for (String s: set) { System.out.println(s); }
須要特別強調的是不容許在迭代期間刪除或添加元素,將會引起:java.util.ConcurrentModificationException
異常,意思是不容許併發修改
那麼咱們如何刪除元素呢?
//刪除或添加單個元素: ArrayList<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String s: list) { list.add("11111"); break;//操做完成後直接break; } //刪除或添加多個元素方法1 //先保存須要刪除的元素,迭代完成在一併刪除 ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); ArrayList deletes = new ArrayList(); for (Integer i: list) { if (i > 1){ deletes.add(i); } } list.removeAll(deletes); //刪除或添加多個元素方法2 //使用lambda表達式 jdk1.8以後可用 list.removeIf(i -> i > 1); //刪除或添加多個元素方法3 //迭代copy的集合,從原始集合刪除 for (Integer i: (ArrayList<Integer>)list.clone()) { if(i > 1){ list.remove(i); } } //刪除或添加多個元素方法4 //使用迭代器 Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()){ if (iterator.next() > 1){ iterator.remove(); } }
//HashMap,不是Collection的子類因此不能直接foreach //可用使用下面幾種方式: //方法1 for ( String key: map.keySet()) { System.out.println(key+" "+map.get(key)); } //方法2 for (Map.Entry entry:map.entrySet()){ System.out.println(entry.getKey() +" "+entry.getValue()); }
HashMap內部使用hash表(本質是一個數組見圖一)
HashMap使用hash算法計算獲得存放的索引位置,一次來加快查詢速度,(比ArrayList還要快)
hash值相同不能表示key徹底相同,須要調用equals再次確認
若是說key的hash值相同可是equals判斷不相同,那麼使用樹結構或者鏈表來存儲這些hash相同的元素,(具體使用哪一種根據當前map中元素的數量,超過64個元素則使用樹結構)
代碼在putVal方法的最後,當添加元素後的大小超過閾值時則直接擴容hash表
總結:
HashMap是使用Hash表(本質是數組)來存儲數據,
當keyHash值相同可是equals判斷不一樣時使用鏈表(添加快,查詢慢)
當元素數量超過64時則將鏈表轉爲數結構(添加慢,查詢快)
最後再來一張框架圖,幫助理解:
圖中的Listiterator 能夠實現倒敘迭代,須要的話諮詢查詢API