集合(上)
Collection和Map兩種集合體系
-
Collection接口:單列數據,定義了存取一組對象的方法的集合
- List:元素有序、可重複的集合
- Vector
- ArrayList
- LinkedList
- Set:元素無序、不可重複的集合
- HashSet
- LinkedHashSet
- TreeSet
- HashSet
- List:元素有序、可重複的集合
-
Map接口:雙列數據,保存具有映射關係“key-value對”的集合
- HsahTable
- Properties
- HashMap
- LinkedHashMap
- TreeMap
- HsahTable
Collection接口的方法
-
添加:add(Object obj)、addAll(Collection coll)
-
獲取有效元素的個數:int size()
-
清空集合:void clear()
-
是否是空集合:boolean isEmpty()
-
contains(Object obj):判斷當前集合中是否包含obj,在判斷時會調用obj對象所在類的equals()方法
-
containsAll(Collection coll1):判斷形參coll1中的所有元素是否都存在於當前集合中(全包含)
-
remove(Object obj):從當前集合中移除obj元素。
-
removeAll(Collection coll1):即去差集、從當前集合中移除coll1中所有的元素
Collection coll = new ArrayList(); coll.add(123); coll.add(456); Collection coll1 = Arrays.asList(123,4567); coll.removeAll(coll1); System.out.println(coll);//[456]
-
retainAll(Collection coll1)即求交集:獲取當前集合和coll1集合的交集,並返回給當前集合
Collection coll = new ArrayList(); coll.add(123); coll.add(456); Collection coll1 = Arrays.asList(123,4567); coll.retainAll(coll1); System.out.println(coll);//[123]
-
equals(Object obj):要想返回true,需要當前集合和形參集合的元素都相同,若爲新的類則該類需要重寫equals()方法,否則調用的是Object類的方法無法達到比較目的(若爲基本數據類型,則add()方法已自動裝箱爲包裝類,包裝類已重寫了equals()方法)
-
hashCode():返回當前對象的哈希值
-
toArray():集合 --> 數組:
Object[] arr = coll.toArray();
Arrays.asList():數組 --> 集合:
List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
-
iterator():返回Iterator接口的實例,用於遍歷集合元素
Iterator迭代器接口的方法
【說明】提供一種方法訪問一個容器(container)對象中各個元素,而又不需暴露該對象的內部細節。迭代器模式,就是爲容器而生。Collection接口繼承了java.lang.Iterable接口,該接口有一個**iterator()**方法,那麼所有實現了Collection接口的集合類都有一個iterator()方法,用以返回一個實現了Iterator接口的對象。
-
hasNext() 和next():若下一條記錄無效,直接調用iterator.next()會拋出NoSuchElementException異常
//hasNext():判斷是否還有下一個元素 while(iterator.hasNext()){ //next():①指針下移 ②將下移以後集合位置上的元素返回 System.out.println(iterator.next()); }
-
迭代器的執行原理
- 集合對象每次調用iterator()方法都得到一個全新的迭代器對象,默認遊標都在集合的第一個元素之前
-
default void remove():通過迭代器對象的remove方法刪除元素,而不是集合對象的remove方法
-
使用增強for循環foreach循環遍歷集合元素的底層用的就是Iterator迭代器!
-
增強for循環foreach的面試題:
String[] arr = new String[]{"MM","MM","MM"}; //方式一:普通for賦值 for(int i = 0;i < arr.length;i++){ arr[i] = "GG"; }//{"GG","GG","GG"} //方式二:增強for循環 for(String s : arr){ s = "GG";//對新的變量賦值不改變原數組的數據 }//{"MM","MM","MM"}
-
List接口的方法
- void add(int index, Object ele):在index位置插入ele元素
- boolean addAll(int index, Collection eles):從index位置開始將eles中的所有元素添加進來
- Object get(int index):獲取指定index位置的元素
- int indexOf(Object obj):返回obj在集合中首次出現的位置
- int lastIndexOf(Object obj):返回obj在當前集合中末次出現的位置
- Object remove(int index):移除指定index位置的元素,並返回此元素
- Object set(int index, Object ele):設置指定index位置的元素爲ele
- List subList(int fromIndex, int toIndex):返回從fromIndex到toIndex位置的子集合
操作 | 方法 |
---|---|
增 | add(Object obj) |
刪 | remove(int index) / remove(Object obj) |
改 | set(int index, Object ele) |
查 | get(int index) |
插 | add(int index, Object ele) |
長度 | size() |
遍歷方式:① Iterator迭代器方式 ② 增強for循環 ③ 普通循環
ArrayList()源碼分析
-
jdk 7情況下:(對象的創建類似於單例的餓漢式)
ArrayList list = new ArrayList();底層創建了長度是10的Object[]數組
list.add(123);//elementData[0] = new Integer(123);//自動裝箱用包裝類添加數據
…
list.add(11);//如果此次的添加導致底層Object[]數組容量不夠,則擴容。
默認情況下,擴容爲原來的容量的1.5倍,同時需要將原有數組中的數據複製到新的數組中。(Arrays.copyOf())
結論:建議開發中使用帶參的構造器避免多次擴容:ArrayList list = new ArrayList(int capacity)
-
jdk 8中ArrayList的變化:(類似於單例的懶漢式,延遲了數組的創建,節省內存)
ArrayList list = new ArrayList();底層Object[]數組,初始化爲{}.並沒創建長度爲10的數組
list.add(123);第一次調用add()時,底層才創建了長度10的數組,並將數據123添加到elementData[0]
…
後續的添加和擴容操作與jdk 7無異。
Vector的源碼分析
-
jdk7和jdk8中通過Vector()構造器創建對象時,底層都創建了長度爲10的Object[ ]數組。
-
在擴容方面,默認擴容爲原來的數組長度的2倍。
面試題:ArrayList、LinkedList、Vector三者的異同?
-
同:三個類都是實現了List接口,存儲數據的特點相同:存儲有序的、可重複的數據
-
不同:
List實現類 底層結構 同步 特點 Vector 可變數組Object[ ] 單線程(同步低效) 老 ArrayList 可變數組Object[ ] 多線程(異步高效) 查詢快 LinkedList 雙向鏈表 多線程(異步高效) 增刪操作快