ArrayList
-
ArrayList底層記憶體結構
-
ArrayList的擴容機制
-
深、淺拷貝
一些關鍵概念
標記介面:決議到標記介面,做一些處理
RandomAccess:表明該類支持隨機訪問(下標訪問,就是告訴別人你底層用的是陣列)
Cloneable:表明該類支持克隆(深拷貝,淺拷貝)
/*
JDK1.7字串常量池是在堆(常量池)中的
JDK1.8做了優化,出現一個新概念:元空間(又叫非堆),元空間并不在虛擬機中,而是使用本地記憶體(可調節)
*/
String aa=new String("aa");
String bb="a"+"a";
System.out.println(aa==bb);//false 指標相同,但是不相等
System.out.println(aa.hashCode());
System.out.println(bb.hashCode());
System.out.println(aa.equals(bb));//true
String t1="123"+"4";
String t2="1234";
System.out.println(t1==t2);//true String拼接是相同的
System.out.println(("123"+"4").hashCode());
System.out.println("1234".hashCode());
System.out.println(t1.equals(t2));
String r1=new String("123"+"4");
String r2=new String("1234");
System.out.println(r1==r2);//false
System.out.println(r1.hashCode());
System.out.println(r2.hashCode());
System.out.println(r1.equals(r2));//true
Serializable:序列化
public class Demo02 implements Serializable, Cloneable {
private int id=11;
private String name="1231321";
private Demo01 demo01=new Demo01();
//省略set/get
@Override
protected Object clone() throws CloneNotSupportedException {
//第一種方式(比較死板)
Object obj = null;
obj = super.clone();
Demo02 demo02 = (Demo02) obj;
//對參考型別的單獨處理
demo02.demo01 = (Demo01) demo01.clone();
return obj;
}
/**
* <p>使用IO的方式克隆</p>
*
* @return
*/
public Object deepProtoCloneByIO() {
//創建流物件
ByteArrayInputStream bis = null;
ByteArrayOutputStream bos = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);//當前這個物件以物件流的方式輸出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
Demo02 o = (Demo02) ois.readObject();
return o;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
ArrayList組成:
私有屬性:
//默認的容量是10
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//elementData存盤ArrayList內的元素,
/*
transient關鍵字解釋:Java的serialization提供了一種持久化物件實體的機制,當持久化物件時,可能有一個特殊的物件資料成 員,我們不想用serialization機制來保存它,為了在一個特定物件的一個域上關閉serialization,可以在這個域前加上關鍵字 transient
*/
transient Object[] elementData; // non-private to simplify nested class access
//size表示它包含的元素的數量,
private int size;
構造方法:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
//默認是空陣列
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
操作元素的一些方法:
- set(int index, E element)
// 用指定的元素替代此串列中指定位置上的元素,并回傳以前位于該位置上的元素,
public E set(int index, E element) {
//檢驗下他的長度合不合理
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
- add(E e)
// 將指定的元素添加到此串列的尾部,
public boolean add(E e) {
//擴容
/*
先呼叫了ensureCapacity(size+1)方法,之后將元素的索引賦給elementData[size],而后size自增
*/
ensureCapacity(size + 1);
elementData[size++] = e;
return true;
}
- add(int index, E element)
// 將指定的元素插入此串列中的指定位置,
// 如果當前位置有元素,則向右移動當前位于該位置的元素以及所有后續元素(將其索引加1),
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
// 如果陣列長度不足,將進行擴容,
ensureCapacity(size+1); // Increments modCount!!
// 將 elementData中從Index位置開始、長度為size-index的元素,
// 拷貝到從下標為index+1位置開始的新的elementData陣列中,
// 即將當前位于該位置的元素以及所有后續元素右移一個位置,
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element;
size++;
}
- addAll(Collection<? extends E> c)
// 按照指定collection的迭代器所回傳的元素順序,將該collection中的所有元素添加到此串列的尾部,
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
//擴容
ensureCapacity(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
- addAll(int index, Collection<? extends E> c)
// 從指定的位置開始,將指定collection中的所有元素插入到此串列中,
public boolean addAll(int index, Collection<? extends E> c) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: " + index + ", Size: " + size);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
- romove(int index):
/*
首先是檢查范圍,修改modCount,保留將要被移除的元素,將移除位置之后的元素向前挪動一個位置,將list末尾元素置空(null),回傳 被移除的元素,
*/
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
- remove(Object o)
/*
remove(Object o)中通過遍歷element尋找是否存在傳入物件,一旦找到就呼叫fastRemove移除物件,為什么找到了元素就知道了index,不通過remove(index)來移除元素呢?因為fastRemove跳過了判斷邊界的處理,因為找到元素就相當于確定了index不會超過邊界,而且fastRemove并不回傳被移除的元素
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
//這個方法是關鍵
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
//這個方法是關鍵
fastRemove(index);
return true;
}
}
return false;
}
//==============================》fastRemove(int index)
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
擴容機制:
圖解說明:
當ArrayList如果不指定構造個數的話,第一次往里面添加元素時底層陣列會初始化一個長度為10的陣列,看一下ArrayList里的原始碼,當添加第11個元素時

再看grow()方法

再看Arrays.copyOf()方法

代碼說明:
- ensureExplicitCapacity(int minCapacity)
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//這里進行了真正的擴容
grow(minCapacity);
}
- grow(int minCapacity)
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//相當于int newCapacity = oldCapacity + (oldCapacity/2),但性能會好一些,
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
- copyOf(U[] original, int newLength, Class<? extends T[]> newType)
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
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;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/258929.html
標籤:java
