集合的理解和好處
陣列一旦定義,長度即固定,不能修改,要添加新元素需要新建陣列,然后回圈拷貝,非常麻煩
- 集合可以動態保存任意多個物件,使用比較方便
- 提供餓了一系列方便的操作物件的方法:add、remove、set、get等
- 使用集合添加、洗掉新元素的示意代碼,簡潔明了
集合主要是兩組(單列集合,雙列集合)
Collection 介面有兩個重要的子介面,List 和 Set,他們的實作子類都是單列集合,直接存放值
Map介面的實作子類 是雙列集合,存放的是K-V鍵值對
這是Collection介面下體系的主要介面和類體系:

這是Map介面下體系的主要介面和類體系:

1. Collection介面和常用方法
1.1 Collection介面實作類的特點
public interface Collection<E> extends Iterable<E>
- collection實作子類可以存放多個元素,每個元素可以是Object
- 有些Collection的實作類,可以存放重復的元素,有些不可以
- 有些Collection的實作類,有些事有序的(List),有些不是有序的(Set)
- Collection介面沒有直接的實作子類,是通過他的子介面Set和List來實作的
1.2 Collection介面和常用方法
以實作子類ArrayList來演示
void add(E e); //添加單個元素, E是泛型
E remove(int index); //洗掉并回傳指定元素
boolean contains(Object o); //查找某個元素是否存在
int size(); //獲取元素個數
boolean isEmpty(); //判斷是否為空
void clear(); //清空
boolean addAll(Collection<? extends E> c); //添加E集合中的所有元素
boolean containsAll(Collection <?> c); //查找E集合中的元素是否都存在于該集合中
boolean removeAll(Collection<?> c); //移除該集合中所有同時存在于E集合中的元素
1.3 Collection介面遍歷元素方式
1.3.1 使用Iterator(迭代器)
- Iterator物件稱為迭代器,主要用于遍歷Collection集合中的元素
- 所有實作了Collection介面的集合類多有一個iterator()方法,用于回傳一個實作了Iterator介面的物件,即可以回傳一個迭代器
- Iterator的方法和執行原理:
//hasNext(); 判斷是否還有下一個元素
//next(); 1.指標下移,2.將下移以后集合位置上的元素回傳
//remove(); 從底層集合中移移除此迭代器回傳的最后一個元素,每次呼叫next()時,只能呼叫此方法一次,并且如果在迭代程序中,呼叫了除該方法意外的任何方式修改基礎集合,都會破壞迭代器,從而終止迭代,這是為了應對并發問題,因此可以通過實作此方法的時候指定并發修改策略來避免破壞迭代器,
Iterator iterator = coll.iterator();//得到一個集合的迭代器
while(iterator.hasNext()){
//next():
System.out.println(iterator.next());
}
- Iterator僅用于遍歷集合,Iterator本身并不存放物件
提示:在呼叫iterator.next()方法之前,必須要呼叫iterator.hasNext()進行檢測,否則當下一條記錄無效時,呼叫iterator.next()會拋出NoSuchElementException例外,如果需要再次遍歷,需要重置迭代器:iterator=coll.iterator();
1.3.2 使用增強for回圈
增強for回圈的底層仍然是迭代器,所以可以理解成簡化版的迭代器
增強for回圈可以用來遍歷陣列或者Collection集合
for(element:list){
System.out.println(element);
}
2. List介面和常用方法
List介面和Set介面都繼承了Collection介面,因此Collection介面的所有方法,實作了List介面和Set介面的類都擁有,但List介面和Set介面是平級的,因此List介面的方法,Set介面不一定擁有
2.1 List集合基本介紹
- List集合類中元素有序(即添加順序和取出順序一致)、且元素可重復,
- List集合中每個元素都有器對應的順序索引,即支持索引,
- List容器中的元素都對應一個整數型的序號記載器在容器中的位置,可以根據序號存取容器中的元素
- JDK API中List介面的實作類有:AbstractList,AbstractSequentialList , ArrayList , AttributeList , CopyOnWriteArrayList , LinkedList , RoleList , RoleUnresolvedList , Stack , Vector
2.2 List介面的常用方法
List集合里添加了一些根據索引來操作集合元素的方法:
1. void add(int index, E element); //在index位置插入E型別的元素,E是泛型
2. boolean addAll(int index, Collection<? extends E> c); //將c中所有的元素插入index位置,c是實作了Collection介面的E型別的子類
3. E get(int index); //獲取并回傳index位置的元素
4. int indexOf(Object o); //回傳obj在集合中首次出現的位置
5. int lastIndexOf(Object o); //回傳obj在集合中最后出現的位置
6. boolean remove(Object o); //移除指定元素
7. E remove(int index); //移除并回傳指定位置的元素
8. E set(int index, E element); // 回傳index位置的元素,并將此位置元素替換為element
9. List<E> subList(int fromIndex, int toIndex);//回傳從fromIndex到toIndex位置的前閉后開子集合[fromIndex,toIdex)
2.3 ArrayList的注意事項
ArrayList類定義說明:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Aloneable, java.io.Serializable
- ArrayList 可以放入null,并且可以放入多個
- ArrayList是由陣列來實作資料存盤的
- ArrayList基本等同于Vector,ArrayList的執行效率更高,但是執行緒不安全的,因此多執行緒情況下,不建議使用ArrayList
//ArrayList原始碼中,沒有關于執行緒控制的代碼
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
//Vector原始碼中使用Synchronized關鍵字修飾,是執行緒安全的
public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}
//LinkedList也是執行緒不安全的
public boolean add(E e) {
linkLast(e);
return true;
}
2.4 ArrayList的底層操作機制原始碼分析
- ArrayList中維護了一個Object型別的陣列elementData
//transient 關鍵字表示此陣列不會被序列化
transient Object[] elementData; // non-private to simplify nested class access
- 當創建物件時,如果使用的是無參構造器,則初始elementData容量為0.
public ArrayList() {
this.elementData = https://www.cnblogs.com/hiibird/p/DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 當添加元素時:先判斷是否需要擴容,如果需要擴容,則呼叫grow方法,否則直接添加元素到適當位置
- 如果使用的是無參構造器,則第一次添加,需要擴容的話,則擴容elementData為10,如果需要再次擴容的話,則擴容elementData為1.5倍
- 如果使用的時指定容量capacity的構造器,則初始elementData的容量為capacity
- 如果使用的是指定容量capacity的構造器,如果需要擴容,則直接擴容elementData為1.5倍
2.5 ArrayList無參構造器
1. 使用無參構造器初始化一個陣列:
ArrayList<Object> list = new ArrayList<Object>();
-->初始化程序呼叫程序:
-->ArrayList.java
這一步涉及的成員變數:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = https://www.cnblogs.com/hiibird/p/{};
//首先將elementData初始化為空陣列
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2. 回圈添加資料:
for(int i = 1; i <= 10; i++){
list.add(i);
}
-->呼叫程序:
-->ArrayList.java
這一步涉及的成員變數:
private int size; //成員變數,用來記錄陣列串列的大小(包含元素的數量)
private static final int DEFAULT_CAPACITY = 10;
//首先發生int->Integer自動裝箱
//然后呼叫 boolean add(E e)方法,modCount記錄該集合被修改的次數
public boolean add(E e) {
modCount++;
add(e, elementData, size);//size = 0
return true;
}
--> private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)//如果當前陣列已滿
elementData = grow();//呼叫grow函式擴容至10
elementData[s] = e;
size = s + 1;
}
--> Object[] grow(){
return grow(size+1);
}
--> Object[] grow(int minCapacity){//將陣列拷貝到長度為10的新陣列中
return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));
}
--> int newCapacity(int minCapacity){ //return 10;
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity>>1);//新容量為舊容量的(1+0.5)倍
if(newCapacity - minCapacity <= 0){//即如果舊容量為0或1
//如果當前陣列為就是那個空的成員陣列,就回傳10和(當前容量+1)中較大的一個
if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDTA){
return Math.max(DEFAULT_CAPACITY,minCapacity);
}
//block of code unrelated to the operation
}
}
3. 再次回圈添加資料:
for (int i = 11; i <= 15; i++){
list.add;
}
-->呼叫程序:
-->ArrayList.java
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
--> private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)//此時陣列已經存滿了
elementData = grow();//呼叫grow方法再次擴容至10*(1+0.5)=15
elementData[s] = e; //在第10位存入這一輪的資料
size = s + 1;
}
--> private Object[] grow() {
return grow(size + 1);//size = 10
}
--> private Object[] grow(int minCapacity) {//minCapacity = 11,即最小也得11個位置才可以,新陣列不能小于這個數
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
--> private int newCapacity(int minCapacity) {//minCapacity = 11
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//15
if (newCapacity - minCapacity <= 0) {//false
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow //false
throw new OutOfMemoryError();
return minCapacity; //return 15
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
4. 再次添加資料:
list.add(100);//此時由于list.length = 15,容量已經滿了,會再次擴容至22
//
2.5 Vector的基本介紹
- Vector類的定義說明
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
- Vector 底層也是一個物件陣列,protected Object[] elementData;
- Vector是執行緒同步的,即執行緒安全,Vector類的操作方法帶有synchronized
public synchronized void setSize(int newSize) {
modCount++;
if (newSize > elementData.length)
grow(newSize);
final Object[] es = elementData;
for (int to = elementCount, i = newSize; i < to; i++)
es[i] = null;
elementCount = newSize;
}
- 在開發中,需要執行緒同步安全時,考慮使用Vector
2.5.1 Vector和ArrayList的比較
| 集合 | 底層結構 | 版本 | 執行緒安全(同步)效率 | 擴容 |
|---|---|---|---|---|
| ArrayList | 可變陣列 | jdk1.2 | 不安全,效率高 | 如果有參構造,1.5倍;如果是無參構造,第一次10,從第二次開始按1.5倍擴容 |
| Vector | 可變陣列 | jdk1.0 | 安全,效率不高 | 如果是無參,默認10,滿后按2倍擴容;有參構造則按指定大小創建,并每次按2倍擴容,也可以手動指定增量capacityIncrement,每次增加capacityIncrement |
2.6 LinkedList
LinkedList類定義說明
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
- LinkedList實作了雙向鏈表和雙端佇列特點
- 可以天界任意元素(元素可以重復),包括null
- 執行緒不安全,沒有實作同步
2.6.1 LinkedList底層架構
LinkedList的底層操作機制
- LinkedList底層維護了一個雙向鏈表,
- LinkedLsit中維護了兩個屬性first和last分別指向首節點和尾節點
- 每個節點(Node物件)里面又維護了prev、next、item三個屬性,其中通過prev指向前一個,通過next指向后一個節點,最終實作雙向鏈表,
- 所以LinkedList的元素的添加和洗掉,不是通過陣列完成的,相對來說效率較高
2.6.1 ArrayList和LinkedList比較
| 集合 | 底層結構 | 增刪的效率 | 改查的效率 |
|---|---|---|---|
| ArrayList | 可變陣列 | 較低 | 較高 |
| LinkedList | 雙向鏈表 | 較高,通過鏈表追加 | 較低 |
2.6.2 如何選擇ArrayList和LinkedList
- 如果改查的操作多,選擇ArrayList
- 如果增刪的操作多,選擇LinkedList
- 一般來說,在程式中,80%~90%的操作都是查詢,因此大部分情況下會選擇ArrayList
- 在一個專案中,根據業務靈活選擇,也可能這樣,一個模塊使用的是ArrayList,另一個模塊使用的是LinkedList,要根據業務來選擇,
- 這兩個都是執行緒不安全的,在單執行緒程式中使用
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/550089.html
標籤:Java
