详细分析ArrayList集合源码分析以及纯手写ArrayList集合

首先在分析源码前,先了解下几点

1. jdk 1.7之后 数组默认数据大小代码存放在 add方法中 (jdk 1.6默认构造函数初始化elementData大小)

2.arrayList 底层采用数组实现的 数组名称为 elementData

-----ArrayList分析源码开始---

  1. 首先先定义一个ArrayList集合,并添加一个元素方便进行调试,如下图

  1. 通过DEBUG调试进入到ADD方法中

这里的ensureCapacityInternal() size参数默认没赋值

 

  1. 然后进入ensureCapacityInternal中

  1. 然后看到calculateCapacity方法中带了2个参数 一个是 elementData 和 刚传参进来的参数(在这里elementData默认是没有赋值的 跟上面的size一样,只是定义了一下而已)

我们来看一下这个方法干什么用的

在这里可以看到 DEFAULT_CAPACITY 默认数组长度定义为10,最小数组为1 ,将最大数组长度进行比较然后将值比较后的值返回出去
  1. 看到 ensureExplicitCapacity  

modCount++:主要是用来记录修改次数

然后看到grow方法的主要作用是将 当前minCapacity的长度 赋值给 elementData数组长度

  1. 进入到grow方法后可以看到 这一块其实就是ArrayList底层实现数组扩容方法

  1. 看完整个里面的流程后,在回过来看到add方法

在上面的步骤中已经知道了elementData已经被默认赋值长度为10了

elementData[size++] = e; 这个就是将数据存储到数组 size长度下标中

 

看完源码分析之后,就来简单的手写一下ArrayList集合

/**
 *
手写自定义ArrayList集合
 * @author 作者:旷黎明
 * @date 2019.6.18
 */

public class ExtArrayList {
   
/**
     * ArrayList
底层采用数组存放
     */
   
private Object[] elementData;

   
/**
     *
默认数组容量
     */
   
private static final int DEFAULT_CAPACITY = 10;

   
/**
     *
定义一个空数组
     */
   
private static final Object[] EMPTY_ELEMENTDATA = {};

   
/**
     *
记录ArrayList下标长度
     */
   
private int size;

   
/**
     *
指定ArrayList 底层数组初始的容器长度
     * @param initialCapacity
    
*/
   
public ExtArrayList(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);
        }
    }

   
/**
     *
默认初始化容量为10
     *
注意:这里笔者这样写是以1.6的方式写的,1.7是在add方法中初始化容量的
     */
   
public ExtArrayList(){
       
this(DEFAULT_CAPACITY);
    }

   
public boolean add(Object object){
        ensureCapacityInternal(
size + 1);
       
//使用下标进行赋值
        elementData[size++] = object;
       
return true;
    }

   
/**
     *
以下标插入数据
     * @param index
    
* @param object
    
* @return
    
*/
   
public boolean add(int index,Object object){
        ensureCapacityInternal(
size + 1);

       
/**
         *
index下标后面的值 移动到 index + 1 下标上 所以 index下标的值就是无用的值
         *
         * 
  1 2 3 4 5
         *
下标 0 1 2 O 3 4
         */
       
System.arraycopy(elementData,index,elementData,index+1,size - index);
       
//object 覆盖到 index下标中
        elementData[index] = object;
       
//容器数据+1
       
size++;
       
return true;
    }

   
/**
     *
通过下标获取值
     * @param index
    
* @return
    
*/
   
public Object get(int index){
        rangeCheck(index);
       
return elementData[index];
    }

   
/**
     *
判断下标是否越界
     * @param index
    
*/
   
private void rangeCheck(int index) {
       
if (index >= size){
           
throw new IndexOutOfBoundsException("下标越界!!!");
        }
    }

   
/**
     *
判断数组最小容量是否大于初始容量 大于则扩容
     * @param minCapacity
    
*/
   
private void ensureCapacityInternal(int minCapacity) {
       
// overflow-conscious code
       
if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

   
/**
     *
数组扩容
     * @param minCapacity
    
*/
   
private void grow(int minCapacity) {
       
//源数组长度
        int oldCapacity = elementData.length;
        
//新数组长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);

       
/**
         *
如果集合初始长度设置为1,但是需要添加3个元素,那么这个时候在第2个元素就得开始进行扩容
         * 这个时候上面的新数组长度以1.5倍进行扩容(但是java里面是int所以为1)
         *
新数组长度为 1 - 最小容量长度为 2 就无法进行扩容
         * 所以这里的判断就是就是将最小数组容量长度赋值给新数组长度
         * 调试一下 一目了然
         */
       
if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;

//        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //
将新数组长度 copy 源数组长度中 并且将值也copy至其中了
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

   
/**
     *
返回数组长度
     * @return
    
*/
   
public int getSize(){
       
return size;
    }

   
/**
     *
删除下标
     * 删除原理:
     * @param
index
    
* @return
    
*/
   
public Object remove(int index){

       
//1.判断下标是否越界
        rangeCheck(index);
       
//2.计算删除元素后的长度
        int numMoved = size - index - 1;
       
if(numMoved > 0){
           
//将删除元素下标后面的值覆盖到当前下标值上
            System.arraycopy(elementData,index + 1 ,elementData,index,numMoved);
        }
       
//将最后数组的值置空
        elementData[--size] = null;
       
return index;
    }

   
/**
     *
以对象进行删除
     * @param o
    
* @return
    
*/
   
public boolean remove(Object o){
       
if(o != null){
           
for(int i = 0; i < elementData.length; i++){
               
if(o.equals(elementData[i])){
                    remove(i);
                   
return true;
                }
            }
        }
       
return false;
    }
}

最后来进行测试一波

public class TestList {

   
public static void main(String[] args) {

       
/**
         *
添加数据
         */
       
ExtArrayList extArrayList = new ExtArrayList(1);
        extArrayList.add(
"测试1");
        extArrayList.add(
"测试2");
        extArrayList.add(
"测试3");
        extArrayList.add(
"测试4");
        extArrayList.add(
"测试5");


       
/**
         *
遍历数据
         */
       
for(int i = 0; i< extArrayList.getSize();i++){
            System.
out.println(extArrayList.get(i));
        }

       
/**
         *
删除后,查看遍历的数据
         */
       
{
            System.
out.println("<------------ 以下标删除后  ---------->");
            extArrayList.remove(
1);

           
/**
             *
遍历数据
             */
           
for(int i = 0; i< extArrayList.getSize();i++){
                System.
out.println(extArrayList.get(i));
            }
        }
    }
}

 

但是有没有发现现在这个集合没有使用泛型,所以我们现在就把泛型也添加上来

首先定义一个泛型接口

public interface ExtList<E> {


   
public boolean add(E e);

   
public boolean add(int index,E e);

   
public E get(int index);

   
public E remove(int index);

   
public boolean remove(E e);

   
public int getSize();
}

实现泛型接口

/**
 *
手写自定义ArrayList集合
 * @author 作者:旷黎明
 * @date 2019.6.18
 */

public class ExtArrayList<E> implements ExtList<E>{

//这里把上面的方法全部实现过来 即可,我这里偷个懒只实现了一个方法


/**
     *
添加数据
     * @param e
    
* @return
    
*/
   
@Override
   
public boolean add(E e){
        ensureCapacityInternal(
size + 1);
       
//使用下标进行赋值
       
elementData[size++] = e;
       
return true;
    }

}

 

最后在进行测试,成功

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值