浅析ArrayList的内部实现

来源:互联网 发布:新手开淘宝店怎么装修 编辑:程序博客网 时间:2024/05/16 15:13

        ArrayList的特性:可以自由扩展,存储任意多个数字,弥补了数组的定长的缺陷,但是他的内部还是数组!为什么ArrayList可以自由扩展? 下面我们用代码来演示下ArrayList的内部实现!

        首先我们定义一个MyArrayList,既然是集合,集合的内部实现都是数组,我们定义一个MyArrayList里面包含一个Object类型的数组和一个int 类型的size。size是用来存储数组中存储了多少个Object!

publicclass MyArrayList {

       Object []arr=new Object[2];  //定义一个数组

        intsize=0;  //存入了多少数到数组里面的记录!

                         (数组里面有多少个数)当记录数等于数组的长度时就需要扩容

} 

        这样我们自己的MyArrayList就定义好了,在ArrayList中有添加数,在指定位置添加数,根据索引查询,根据索引删除,删除指定对象等方法,用代码来实现:

        首先定义一个添加的方法add(Object object); 我们只需要将传进来的object添加到上面定义好的arr的数组中,但是数组的长度只有2个,当我们添加第三个object的时候,就会越界,下面我们要做的是将arr数组的长度增加!如何做了?

代码实现如下:

/*添加数据,判断扩容*/

publicvoid add(Object num){

       if(arr.length==size){

             Object[]   temp =  new Object[arr.length*3/2+1];

             System.arraycopy(arr, 0, temp, 0,size);

             arr=temp;

      }                                                                                                                                                    

      arr[size++]=num;  //每进一个数就要将记录数++

   }

        下面我们来看下代码的实现

        当我们发现数组的长度等于数组中的记录数的时候,我们知道,数组已经装满了!如果在添加的话就会越界,这时我们就new一个临时数组temp出来,长度比原来数组长度大就行了,然后我们把arr数组里面的数按添加位置,复制到temp中就行了,我们可以使用for循环一个一个的去移,那样速度会慢一点(但数大的时候区别大一些,代码中的方法为源码中的方法,我们借鉴下),我们就是用System.arraycope方法将arr数组按添加位置添加临时数组temp数组中,arraycope方法中五个参数的意思分别是:源(要copy哪个数组,以arr和temp为例)、从arr的0个位置开始copy、copy到temp数组、copy到temp的0个位置、copy多少个长度! 整个意思就是 我们将arr数组中的第0个位置开始一直copy数组中的记录数size个数 copy到temp中从第0个位置开始放置!这样我们的temp数据就比arr数组要大,然后再temp数组整体复制给arr数组就达到了扩容的目的!好了我们第一个方法add(Object object) 方法成功!

       现在是不是迫不及待的测试下自己的MyArrayList的方法add(Object object)是否成功,我们就写一个get(int index)方法就行!在get(int index)方法中我们要做的就是将arr数组中的数据按index索引返回就行。

       代码示例:

public Object get(int index){

      returnarr[index];

   }     

        呵呵! 就这么简单!我们定义好了一个MyArrayList集合!

        然后就是指定索引位置添加数据了!现在我们应该有一个思路,我们的MyArrayList就是一个数组,跟数组不同的就是一个扩容问题,我们把扩容处理好了,就是在对数组操作!

        我们还是先定义一个方法add(Object object)方法重载的方法,add(int index,Object object)方法,要做的三件事,首先是判断数组是否需要扩容,然后是将指定位置后的object整体往后移一位,最后就是将要添加的object添加到指定的index位置了!

代码如下:

publicvoid add(int index,Object object){

      /*传递过来的索引我们首先要判断是否大于数组的长度

       *小于我们就加!否则越界

       *我们还要判断一点的是他什么时候扩容

       */

      if(index<arr.length){

        if(size==arr.length){

           Object []temp=new Object[arr.length*3/2+1];

           System.arraycopy(arr, 0, temp, 0,size);

           arr=temp;

        }

        System.arraycopy(arr, index,arr, index+1,size-index);

       

        arr[index]=object;

        size++;

      }

   }

        分析一下代码上面一个arraycopy是扩容,下面的一个arraycopy是移位,意思是我们将arr数组从传进来的索引位置开始移,还是移到arr数组的传进来的索引位置的后一位(加1就是后一位),这样传进来的索引位置就空出来了,我们在把传进来的object赋值给传进来指定索引位置的arr数组就搞定了!

        测试一下,依然成功!我们已经完成了MyArrayList的三个方法!下面我们在来写remove方法,同样remove方法也是一个重载!remove(int index)是从索引删除,remove(Object object)

这两个方法似乎有冲突,因为int 也继承Object 当我们传一个int进去时会自动找到int而不是Object(相当于一种就近原则,找他的子类,而不会找父类)!

       我们先来写从指定索引删除吧!删除后我们就不管他是否减容吧!我们先来看下remove(int index)这个方法吧!我们要传一个索引进来然后删除!删除之后我们在将index后的object向前移一位就行了!当然要将记录数减1就行了!

publicvoid remove(int index){

      /*先删除指定索引的值,然后移位*/

      if(index<size){         //要有那个数存在才能删除

        System.arraycopy(arr, index+1,arr, index,size-index-1);

        size--;

      }

   }

       上面的方法我们同样用的是arraycopy,我们只需要将arr中的index后一个位开始移起,移到arr的index位,移动为index后面的位数就行了! 相当于我们直接把arr的index给覆盖掉就行!

       下面在写remove(Object object)方法,想一下,我们已经能够通过索引删除元素了,我们只要找到传进来的object的索引然后传进去就KO了

看下代码

publicvoid remove(Object object){

       for(int i=0;i<arr.length;i++){

             if(arr[i].equals(object)){

                  remove(i);  //调用写好的通过索引删除

             }

      }

}

我们通过循环找到索引后传到remove(int index)里面就达到了删除的目的!

关于ArrayList里面的一些简单方法就完成了!似乎没有想象中的那么难!

下面我们看下关于ArrayList内部的实现的一些方法!

首先他定义的一个add(Object object)方法吧!

publicboolean add(E o) {

        ensureCapacity(size + 1); // Increments modCount!!

        elementData[size++] = o;

        returntrue;

}

publicvoidensureCapacity(int minCapacity) {

        modCount++;

   int oldCapacity =elementData.length;

   if (minCapacity > oldCapacity) {

       Object oldData[] = elementData;

       int newCapacity = (oldCapacity * 3)/2 + 1;

         if (newCapacity < minCapacity)

      newCapacity = minCapacity;

       elementData = (E[])new Object[newCapacity];

               System.arraycopy(oldData, 0, elementData, 0, size);

         }

}

同样也是不够用就扩容!在new数组的时候 前面加上了(E[])从List继承而来,可以支持泛型!

Add(int index,Object object)

publicvoidadd(int index, E element) {

   if (index >size || index < 0)

        thrownew IndexOutOfBoundsException( "Index: "+index+", Size: "+size);

        ensureCapacity(size+1); // Increments modCount!!

        System.arraycopy(elementData, index,elementData, index + 1, size - index);

   elementData[index] = element;

   size++;

}

当传进来的添加的指定位置的索引大于数组的记录数或是小于0将抛出异常!

否则调用扩容,然后就是移位!


0 0
原创粉丝点击