绳锯木断水滴石穿之ArrayList的学习与探索之路

绳锯木断水滴石穿之ArrayList的学习与探索之路

前言

作为一个刚刚经历过面试洗礼的小码农,感触真的是颇深。平时工作中很多东西只知道如何使用,并不知道其原理。所以面试中也吃了不少的亏。为了避免这种问题再次发生,故在接下来的一阶段时间内,我都会认真的学习平时用到的技术,并阅读源码,最后以博文的方式总结出来。另外由于刚开始写技术总结类的博文,由于个人水平有限,若有不足的部分望各位看客大人多多批评指正~。

ArrayList初体验

ArrayList作为我们平时工作中经常使用到的集合之一,它里面有哪些方法呢?又是如何实现的呢?下面我们结合着它里面的方法自己手写一个。首先它的常用的方法如下图所示:
在这里插入图片描述

首先我们创建一个接口MyArrayList ,定义上图中的那些方法

package com.qyf.util;
public interface MyArrayList {
	 //集合的大小
	 public int size() ;
	 //集合是否为空
	 public boolean isEmpty();
	 //集合是否包含某个值
	 public boolean contains(Object o);
	 //集合中存储对象o的最小下标
	 public int indexOf(Object o);
	 //集合中存储对象o的最大下标
	 public int lastIndexOf(Object o);
	 // 返回添加是否成功
	 boolean add(Object object);
	 // 返回删除旧值
	 Object remove(int index);
	 // 获取索引位置的值
	 Object get(int index);
}

然后我们创建一个接口实现类MyArrayListImpl,然后实现接口的方法,个人认为第一次学习直接把源码中的方法复制过来、理解、实现功能。后续可以自己根据实现的功能自己手写,甚至加一些自己个性化的功能。

package com.qyf.util;

import java.util.Arrays;

public class MyArrayListImpl implements MyArrayList{

	@Override
	public int size() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean isEmpty() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean contains(Object o) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int indexOf(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int lastIndexOf(Object o) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean add(Object object) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Object remove(int index) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object get(int index) {
		// TODO Auto-generated method stub
		return null;
	}}

此时,手写一个简易版的ArrayList的准备工作就做好了。下一步就是看源码是如何实现这些方法的。
1.基本属性介绍: 这些属性的值在实际的方法中使用到再看具体的含义即可

//定义空数组
private transient Object[]elmentData;
//定义集合存储数据的数目
private int size;
//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认的数组的大小
private static final int DEFAULT_CAPACITY = 10;
//修改次数
protected transient int modCount = 0;
//数组的扩容的最大值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2.构造方法: 源码中有三种构造方法:构造一个空容量的集合ArrayList() ,构造一个具有初始容量的集合ArrayList(int initialCapacity) ,构建一个包含指定集合的元素的集合ArrayList(Collection<? extends E> c) 。本文针对前两种方式进行阐述。
ArrayList(int initialCapacity):

public MyArrayListImpl(int i) {
	// 初始化数组 当执行MyArrayList mt=new MyArrayListImpl(5);的时候就会构建一个容量为5的集合
	if(i<0){
		throw new IllegalArgumentException("非法的初始化容量:"+i);
	}else{
	//给前面定义的elmentData属性赋值
		elmentData=new Object[i];
		System.out.println("初始化容量为:"+i);
	}
}

ArrayList():

public MyArrayListImpl() {
	// 初始化数组
	//此处是给elmentData赋值一个空的数组。也可以自己定义一个默认初始化容量;
	//如默认构建一个初始容量为20的集合,只需要调用一下MyArrayListImpl(int i) 这个方法即可
	this.elmentData=EMPTY_ELEMENTDATA;
	System.out.println("执行MyArrayListImpl的构造方法完成");
}

3.add()方法

@Override
public boolean add(Object object) {
		//确定存储size+1个元素是否需要扩容
	  ensureCapacityInternal(size + 1);  // Increments modCount!!
	  //将对象添加到数组中,并将size的值加1
	  elmentData[size++] = object;
	  System.out.println("添加后size的值:"+size);
      return true;
}
 private void ensureCapacityInternal(int minCapacity) {
		 //若elmentData 是空数组,则赋一个默认值
        if (elmentData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //确定存储size+1个元素是否需要扩容
        ensureExplicitCapacity(minCapacity);
    }
 private void ensureExplicitCapacity(int minCapacity) {
	    //修改次数加1
        modCount++;
        // 若存储的数目(size+1)大于数组容量,则需要扩容
        if (minCapacity - elmentData.length > 0)
        //调用扩容方法
            grow(minCapacity);
    }
 private void grow(int minCapacity) {
        // 旧数组大小
        int oldCapacity = elmentData.length;
        //新数组大小 
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //当elmentData为空的时候存在这个条件
        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:
        //将旧的数组数据复制到新的数组中,完成数组扩容
        elmentData = Arrays.copyOf(elmentData, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

4.size()方法

public int size() {
//由于添加或者移除元素,size的值都是跟着变化的,直接返回size就可以了
        return size;
    }

5.isEmpty()方法

 public boolean isEmpty() {
    //直接判断size是否等于0 就可以知道数组集合是否为空
        return size == 0;
    }

6.indexOf()方法

public int indexOf(Object o) {
	//顺序遍历数组中元素,判断是否与传入的对象o相等,若相等则返回下标i,否则返回-1
	if (o == null) {
        for (int i = 0; i < size; i++)
            if (elmentData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elmentData[i]))
                return i;
    }
    return -1;
}

7.lastIndexOf()方法

public int lastIndexOf(Object o) {
	//倒序遍历数组中元素,判断是否与传入的对象o相等,若相等则返回下标i,否则返回-1
	if (o == null) {
        for (int i = size-1; i >= 0; i--)
            if (elmentData[i]==null)
                return i;
    } else {
        for (int i = size-1; i >= 0; i--)
            if (o.equals(elmentData[i]))
                return i;
    }
    return -1;
}

8.contains()方法

public boolean contains(Object o) {
	//调用indexOf函数,若函数返回值大于等于0,则说明集合里面包含对象o
	return indexOf(o) >= 0;
}

9.get()方法

public Object get(int index) {
 //校验传入的参数是否超出数组最大下标
	rangeCheck(index);
//获取对应的数组中存储的值
    return elmentData(index);
}

Object elmentData(int index) {
    return (Object) elmentData[index];
}
private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

10.remove()方法

public Object remove(int index) {
	//校验传入的参数是否超出数组最大下标
	rangeCheck(index);
	//变更次数+1
    modCount++;
    //获取集合中传入的下标值对应的元素,用于返回
    Object oldValue = elmentData(index);
	//判断是否移除的是否是数组的最后一位。若是最后一位,则直接将最后一位置为null即可
	//否则将数组重新排序
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elmentData, index+1, elmentData, index,
                         numMoved);
    elmentData[--size] = null; // clear to let GC do its work

    return oldValue;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值