下文帶/**/為原始碼注釋//為個人注釋,源代碼使用這個顏色
Vector可以設定增量的集合
add(e)擴容增量值得使用
add(idx,e)末尾追加還是任意插入?
set(idx,ele)替換陣列元素
get(idx)根據陣列下標獲取
remove(idx)使用本地方法復制陣列
remove(obj)洗掉第一個匹配的元素
setSize()擴容還是截斷?
ArrayList和Vector的區別
Vector可以設定增量的集合
/*存盤矢量分量的陣列緩沖區,向量的容量是這個陣列緩沖區的長度,并且至少足夠大來包含向量的所有元素,*/
//存放集合元素的陣列
protected Object[] elementData;
/*當矢量的大小大于其容量時,其容量自動增加的數量,如果容量增量小于或等于零,則每次需要增長時,向量的容量就增加一倍,*/
//應該是集合擴容時用到的,它的作用還有待考
protected int capacityIncrement;
//集合的長度,默認是0
protected int elementCount;
/*構造一個空向量,以便其內部資料陣列的大小為10,其標準容量增量為零,*/
public Vector() {
this(10);
}
/*構造一個具有指定初始容量且容量增量為零的空向量,*/
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
/*構造一個具有指定初始容量和容量增量的空向量,*/
public Vector(int initialCapacity, int capacityIncrement) {
super();
//如果初始容量小于0報錯
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//創建一個容量10的陣列
this.elementData = https://www.cnblogs.com/zumengjie/p/new Object[initialCapacity];
//增量為0
this.capacityIncrement = capacityIncrement;
}
add(e)擴容增量值得使用
/*將指定的元素追加到此向量的末尾,*/
//加鎖了
public synchronized boolean add(E e) {
modCount++;
//第一次添加傳入引數為elementCount=0 (0+1)
//第二次添加傳入引數為elementCount=1 (1+1)
//第三次添加傳入引數為elementCount=2 (2+1)
//第四次添加傳入引數為elementCount=3 (3+1)
//第五次添加傳入引數為elementCount=4 (4+1)
//第六次添加傳入引數為elementCount=5 (5+1)
//第七次添加傳入引數為elementCount=6 (6+1)
//第八次添加傳入引數為elementCount=7 (7+1)
//第九次添加傳入引數為elementCount=8 (8+1)
//第十次添加傳入引數為elementCount=9 (9+1)
//第十一次添加傳入引數為elementCount=10 (10+1)
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
//集合錯誤長度這個值是 -2147483649
public static final int MAX_VALUE = https://www.cnblogs.com/zumengjie/p/0x7fffffff;
//集合最大長度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/*這實作了ensureCapacity的非同步語意,該類中的同步方法可以在內部呼叫此方法以確保容量,而不會產生額外同步的開銷,*/
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
//判斷是否擴容,初始容器是10第11次添加才會觸發擴容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//第11次添加這里傳入的值是11
private void grow(int minCapacity) {
// overflow-conscious code
//elementData.length=10
int oldCapacity = elementData.length;
//capacityIncrement>0 false
//newCapactiy=10+10,在這能看出來,如果自己設定了增量
//那么每次擴容則按照增量值為標準
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);
//什么情況下這里才能<0如果沒有傳遞增量,newCapctiy都是oldCapacity的兩倍
//如果傳遞了,不能是0也不能是負數就算是1那么11-11也不<0
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//這里表示如果新的容量大于了閾值這個閾值是Integer.MAX_VALUE - 8;
//到這里newCapacity肯定是正數也就是只有大于MAX_ARRAY_SIZE才是>0
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//最后拷貝陣列,ArrayList也是這個方法拷貝的,這次進去看看
elementData = https://www.cnblogs.com/zumengjie/p/Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
//這個條件不會滿足
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//如果大于了則是負數其實也是錯誤的,否則使用最大值MAX_ARRAY_SIZE
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
//這是Arrays的方法
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
//三個引數是原陣列,擴容長度,陣列型別
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
//判斷陣列型別是不是Object如果是直接創建一個Object型別的陣列
//如果不是則創建一個指定型別的陣列,newInstance后邊也是本地方法
//最后呼叫本地方法System.arraycopy,關于這個方法的引數在ArrayList
//中聊過這里不展開說了
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
add(idx,e)末尾追加還是任意插入?
/*
將指定元素插入到此向量的指定位置,將元素當前的位置(如果有的話)
和后續的元素向右移動(在它們的索引中添加一個),
*/
public void add(int index, E element) {
insertElementAt(element, index);
}
/*
將指定的物件作為組件插入到這個向量中指定的{@code索引}處,
這個向量中索引大于或等于指定的{@code索引}的每個組件向上
移動,使其索引值比之前的值大1,
*/
//方法加鎖了,引數是要添加得元素和下標
public synchronized void insertElementAt(E obj, int index) {
//計數器
modCount++;
//在這里限定了如果下標大于當前集合總長度則報錯,
//也就是說index最多只能是集合size,推幾行資料
//A:elementCount=0,index可以=0
//B:elementCount=1,index可以=0,1
//C:elementCount=2,index可以=0,1,2
//D:elementCount=3,index可以=0,1,2,3
//E:elementCount=4,index可以=0,1,2,3,4
//F:elementCount=5,index可以=0,1,2,3,4,5
//如果index==elementCount說明是往陣列末尾追加元素
//如果index<elementCount是什么情況呢?
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
//這個方法控制陣列是否擴容,假設我們陣列當前不滿足10則不會觸發第一次擴容
//跳過這個方法繼續看
ensureCapacityHelper(elementCount + 1);
//arraycopy的引數是:源陣列,從這個位置開始復制,目標陣列,從這個位置開始放,復制幾個元素
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
elementCount++;
}
//如果是A情況實參為(設元素型別是Integer):[0,0,0,0,0,0,0,0,0,0],0,[0,0,0,0,0,0,0,0,0,0],1,0
//結果其實是沒有對陣列進行任何操作的,因為要復制的元素為0個,
//最后執行elementData[0]=obj其實就是在陣列0的位置放了元素,這個結果相當于追加
//如果是B情況則可以有兩個index分別是0,1先來看1的,
//[8,0,0,0,0,0,0,0,0,0],1,[8,0,0,0,0,0,0,0,0,0],2,0
//在這種情況下還是沒有任何操作,最終最后執行elementData[0]=obj
//來看B情況的index=0
//[8,0,0,0,0,0,0,0,0,0],0,[8,0,0,0,0,0,0,0,0,0],1,1
//結果是[8,8,0,0,0,0,0,0,0,0]
//然后在執行elementData[1]=obj,把下標0的替換掉[9,8,0,0,0,0,0,0,0,0]
//這樣的結果就是index位置插入原有的往后挪,
//最后看一個C情況它可選的index是0,1,2
如果是2則[8,9,0,0,0,0,0,0,0,0],2,[8,9,0,0,0,0,0,0,0,0],3,0
只要最后一個實參是0則表示要諾的元素就是0個,則沒有任何改變,
最后執行elementData[0]=obj結果是[8,9,7,0,0,0,0,0,0,0],追加
如果是1則[8,9,0,0,0,0,0,0,0,0],1,[8,9,0,0,0,0,0,0,0,0],2,1
結果為:[8,9,9,0,0,0,0,0,0,0]執行elementData[1]=obj結果為[8,7,9,0,0,0,0,0,0,0]后挪
如果是0則[8,9,0,0,0,0,0,0,0,0],0,[8,9,0,0,0,0,0,0,0,0],1,2
結果是:[8,8,9,0,0,0,0,0,0,0]執行elementData[0]=obj結果為[7,8,9,0,0,0,0,0,0,0]后挪
set(idx,ele)替換陣列元素
/*將向量中指定位置的元素替換為指定元素,*/
//加鎖了
public synchronized E set(int index, E element) {
//index不能超過當前集合的長度,也就規定了只能是替換
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
//根據下標獲取old值
E oldValue = https://www.cnblogs.com/zumengjie/p/elementData(index);
//在下標位置設定新值
elementData[index] = element;
//回傳old
return oldValue;
}
get(idx)根據陣列下標獲取
/**回傳向量中指定位置的元素,**/
//加鎖了
public synchronized E get(int index) {
//index必須小于集合size
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
//回傳
return elementData(index);
}
remove(idx)使用本地方法復制陣列
/*移除向量中指定位置的元素,將后面的元素向左移動(從它們的索引中減去1),回傳從向量中洗掉的元素,*/
public synchronized E remove(int index) {
//計數器
modCount++;
//index大于等于size拋出例外
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
//被洗掉的元素
E oldValue = https://www.cnblogs.com/zumengjie/p/elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
設當前集合為[a,b,c,d,e]要洗掉a則index=0
numMoved=5-0-1=4
arraycopy的引數串列為[a,b,c,d,e],1,[a,b,c,d,e],0,4
結果為[b,c,d,e,e],最后elementData[- -5]=null結果為[b,c,d,e,null]
設當前集合為[a,b,c,d,e]要洗掉b則index=1
numMoved=5-1-1=3
arraycopy的引數串列為[a,b,c,d,e],2,[a,b,c,d,e],1,3
結果為[a,c,d,e,e],最后elementData[- -5]=null結果為[a,c,d,e,null]
設當前集合為[a,b,c,d,e]要洗掉e則index=4
numMoved=5-4-1=0
arraycopy的引數串列為[a,b,c,d,e],5,[a,b,c,d,e],4,0
最后一個引數為0表示不移動則這個方法無意義,
最后執行elementData[- -5]=null結果為[a,b,c,d,null]
remove(obj)洗掉第一個匹配的元素
/*洗掉此向量中第一次出現的指定元素,如果向量不包含該元素,則該元素不變*/
public boolean remove(Object o) {
return removeElement(o);
}
/*
從此向量中洗掉引數的第一個(索引最低的)出現,如果在這個向量中找到了物件,
那么向量中索引大于或等于該物件索引的每個分量都向下移動,使其索引值小于它之前的值,
*/
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
public int indexOf(Object o) {
return indexOf(o, 0);
}
/*
回傳指定元素在此向量中第一次出現的索引,從{@code index}向前搜索,或者如果沒有找到該元素,回傳-1,
*/
//查詢元素的下標
public synchronized int indexOf(Object o, int index) {
//如果是null則回圈判斷null,從0開始
if (o == null) {
for (int i = index ; i < elementCount ; i++)
if (elementData[i]==null)
return i;
} else {
//如果不是null則回圈呼叫元素的equals方法,從0開始
for (int i = index ; i < elementCount ; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
/*
洗掉指定索引處的組件,在這個向量中,索引大于或等于指定的{@code索引}的
每個組件都向下移動,使其索引值比之前的值小1,這個向量的大小被減少了{@code 1},
*/
public synchronized void removeElementAt(int index) {
//計數器
modCount++;
//下標越界
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
//下標小于0
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
//下邊的邏輯就跟remove(idx)差不多了,呼叫arraycopy()
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
setSize()擴容還是截斷?
/*
設定這個向量的大小,如果新的大小大于當前大小,新的{@code null}項將被添加到向量的末尾,
如果新大小小于當前大小,索引{@code newSize}和更大的所有組件將被丟棄,
*/
//加鎖了
public synchronized void setSize(int newSize) {
modCount++;
//如果新的size大于原來的,則直接選擇擴容,擴容的方式上邊有解釋
if (newSize > elementCount) {
ensureCapacityHelper(newSize);
} else {
//從新的size開始往后所有的值都置為null
for (int i = newSize ; i < elementCount ; i++) {
elementData[i] = null;
}
}
//重新賦值size
elementCount = newSize;
}
ArrayList和Vector的區別
1 容量初始化時機
ArrayList如果使用無參構造器,則集合的容量在第一次添加時擴容為10
Vector如果使用無參構造,Vector會位元組設定一個10的容量
2 擴容因子
ArrayList不能手動設定擴容因子,Vector可以通過構造引數設定擴容因子
3 擴容演算法
ArrayList擴容的演算法是 newsize=oldsize+oldsize/2
Vector擴容的演算法是 newsize=oldsize+oldsize或者newsize=oldsize+擴容因子
4 同步和非同步
ArrayList的增刪改查均沒有加鎖
Vector的增刪改查均加的有 synchronized
5 更改size
ArrayList不能手動更改size
Vector可以手動設定size
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/3007.html
標籤:Java
上一篇:LeetCode–洗掉鏈表的節點
