手动实现ArrayList
Posted cmg219
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手动实现ArrayList相关的知识,希望对你有一定的参考价值。
目标:手动实现一个ArrayList,然后分析JDK ArrayList的源码
/**
* rangeCheck(),检查数组下标是否越界;
* add(),在某个下标位置添加元素;
* resize(),动态扩容,当数组容量满或者空闲整个数组的3/4时,重新定义容量;
* get(),获取某个位置的元素值;
* set(),设置某个下标的元素值;
* remove(),移除某个下标对应的值;**/
public class MyArrayList<E> {
private int size;//数组长度
private Object elementData[];//保存数组元素
//无参构造函数
public MyArrayList(){
this.elementData=new Object[10];
}
//带参构造函数
public MyArrayList(int initialCapacity){
if(initialCapacity>=0){
this.elementData=new Object[initialCapacity];
}else{
throw new RuntimeException("非法输入初始化容量:"+initialCapacity);
}
}
public int getSize(){
return size;
}
public int getCapacity(){
return elementData.length;
}
public boolean isEmpty(){
return size == 0;
}
public void rangeCheck(int index){
if(index < 0 || index >= size)
throw new IllegalArgumentException("Index is Illegal!");
}
public void add(int index,E e){
if(index<0||index>size){
throw new IllegalArgumentException("index is illegal!");
}
if(size==elementData.length){
resize(elementData.length);
}
//把index后的元素后移
for(int i=size-1;i>index;i--){
elementData[i+1]=elementData[i];
}
elementData[index]=e;
size++;
}
//末尾添加
public void add(E e){
add(size,e);
}
private void resize(int minCapacity){
int newCapacity=minCapacity+minCapacity<<1;
Object[]newData=new Object[newCapacity];
for(int i=0;i<size;i++){
newData[i]=elementData[i];
}
elementData=newData;
}
public E remove(int index){ // remove data[index] and return the value
rangeCheck(index);
E res = (E) elementData[index];
for(int i = index; i < size-1; i++){
elementData[i] = elementData[i+1];
}
size--;
elementData[size] = null;//loitering objects != memory leak
return res;
}
public E get(int index){
rangeCheck(index);
return (E)elementData[index];
}
public void set(int index,E e){
rangeCheck(index);
elementData[index]=e;
}
@Override
public String toString() {
return "MyArrayList{" +
"elementData=" + Arrays.toString(elementData) +
'}';
}
}
以上是我自己实现的MyArrayList,数组的扩容是新建一个数组来代替原来数组,阅读ArrayList源码后发现,它是通过调用ensureCapacityInternal方法进行扩容,每次扩容为原来大小的1.5倍,但是当第一次添加元素或者刘表重元素个数小于10的话,列表容量默认为10.
以add方法为例,add的源码为:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保内部数组有足够的空间
elementData[size++] = e; //将元素加入到数组的末尾,完成添加
return true;
}
如果继续往下Debug
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//数组若是等于空且数组元素个数小于10,就会将数组长度设置为10,大于10则为minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//将数组扩容
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);
}
可以看到,只有在数组容量不满足需求时,会调用Arrays.copyOf方法拷贝数组,所以初始化一个大小合理的数组队性能很有帮助。
以上是关于手动实现ArrayList的主要内容,如果未能解决你的问题,请参考以下文章