手写一个简单的ArrayList
public class ArrayListDemo{
private int[] ints;
private int size = 0;
//初始化数组
public ArrayListDemo() {this(10);}
public ArrayListDemo(int initialCapacity) {ints = new int[initialCapacity];}
//按索引获取值
public int get(int index){
if (index > ints.length - 1) {
System.out.println("index error");
return -1;
}else {
return ints[index];
}
}
//获取数组长度
public int size(){
return ints.length;
}
//返回一个实例化的数组
public int[] toList(){
return ints;
}
//根据索引移除元素
public boolean remove(int index){
int j = index;
if (index >= ints.length) {
return false;
}else {
while (j<ints.length - 1){
j++;
ints[index] = ints[j];
index++;
}
return true;
}
}
//添加数据
public boolean add(int num){
if (size>ints.length){
grow();
}
ints[size] = num;
size++;
return true;
}
//按索引添加数据
public void set(int index,int num){
while (index >= ints.length) {
grow();
}
ints[index] = num;
}
//扩容
public void grow(){
int newCapacity = ints.length + ( ints.length >> 1 ) ;
int[] newInts = new int[newCapacity];
for (int i = 0; i < ints.length; i++) {
newInts[i] = ints[i];
}
ints = newInts;
}
}
Vector与ArrayList的实现相似,但由于Vector里的方法使用了synchronized关键字修饰,所以开销较大;Vector默认每次扩容为自身的两倍,而ArrayList为自身的1.5倍
Vector的扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//capacityIncrement可以在创建Vector的时候设置,自定义每次扩容的大小
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
ArrayList的扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
总结:
Vector使用synchronized修饰方法,所以是线程安全的,默认每次扩容为自身的2倍
ArrayList是线程不安全的,每次扩容为自身的1.5倍
ArrayList实现线程安全的方法:
//使用Collections.synchronizedList(); 得到一个线程安全的 ArrayList。
ArrayList<Object> list = new ArrayList<>();
Collections.synchronizedCollection(list);
//使用concurrent包下的CopyOnWriteArrayList()类
CopyOnWriteArrayList<String> list1 = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList
读写分离的ArrayList
读取数据是在原数组上进行的
写则是在复制数组下进行的(写操作使用的锁为J.U.C包下的 ReentrantLock)
private static int indexOf(Object o, Object[] elements,
int index, int fence) {
if (o == null) {
for (int i = index; i < fence; i++)
if (elements[i] == null)
return i;
} else {
for (int i = index; i < fence; i++)
if (o.equals(elements[i]))
return i;
}
return -1;
}
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
CopyOnWriteArrayList 在写操作的同时允许读操作,大大提高了读操作的性能,因此很适合读多写少的应用场景。
但是 CopyOnWriteArrayList 有其缺陷:
内存占用:在写操作时需要复制一个新的数组,使得内存占用为原来的两倍左右;
数据不一致:读操作不能读取实时性的数据,因为部分写操作的数据还未同步到读数组中。
所以 CopyOnWriteArrayList 不适合内存敏感以及对实时性要求很高的场景。