ArrayList的底层原理及手写实现

ArrayList的底层原理

ArrayList的底层是一个动态的数组,数组的长度可以根据实际存储元素数量的增加而动态增长。
ArrayList的扩容机制:ArrayList的底层数组长度可以通过有参的构造方法给定,也可以通过无参的构造方法默认给定,默认长度是10,存储的元素会从第一个存储单元开始逐个存储,一旦存满,就会触发扩容机制。当需要扩容时,会先申明一个新的数组,它的长度是原数组长度的1.5倍,然后把原来数组中的元素逐一复制到新的数组中,然后把新数组作为ArrayList的底层数组(即更新引用),最后把要添加的那个元素添加到数组中。1.5倍的扩容可以减少空间的浪费,同时也足够承载新的元素。需要注意的是,ArrayList的查询的复杂度是确定的,但是添加元素的复杂度,还需要算上偶尔触发的扩容行为花费的时间复杂度,它是一个平均值。
ArrayList的优缺点分析:Arraylist的长度可以动态变化,在一定程度上弥补了数组的不足,但是每次触发扩容,都意味着要进行一次整个数组的复制,这会产生很大的时间复杂度。 ArrayList底层数组的实现保证了它很快的查找速度,但是在删除和添加元素操作时,效率比同为List集合下的LinkedList(双链表)低很多。
ArrayList的底层安全:ArrayList不是线程安全的,而Vector是线程安全的,Vector的底层方法多了synchronize关键字,确保在同一时间,只能有一个线程获得锁并访问这些方法;这两者的比较可以类似于HashMap和HashTable的比较。为什么我们还是会选择不是线程安全的ArrayList而越来越少使用Vector呢?因为ArrayList的效率很高,尤其体现在查询方面,支持了多线程的并发查询,效率是工程中永恒的话题。为了避免非线程安全的ArrayList在高并发下的一系列问题,我们可以通过在ArrayList的上层使用加锁来规范,比如在修改数据的时候确保只能有一个线程进行操作,而查询就不加限制,实现了高效率性,高灵活性,高安全性。

ArrayList的手写实现

接下来教大家如何手写实现一个简单的ArrayList:
实现的方法有:

 int size();
 MyArrayList();
 MyArrayList(int initialCapacity);
 boolean isEmpty(); 
 Object get(int index);
 boolean add(Object obj);
 void add(int index,Object obj)
 Object remove(int index)
 boolean remove(Object obj)
 Object set(int index,Object obj)
 void rangeCheck(int index)
 void ensureCapacity()

MyArrayList

public class MyArrayList {
	private int size;
	private Object[] elementData;	
	/**
	 * 无参构造方法,
	 * 初始化size为0
	 * 初始化一个数组,大小为10
	 */
	public MyArrayList()
	{
		this.size=0;
		this.elementData=new Object[10];
	}	
	/**
	 * 有参构造方法
	 * 定义数组的初始化大小
	 * @param initialCapacity
	 */
	public MyArrayList(int initialCapacity)
	{
		if(initialCapacity<0)
		{
			try
			{
				throw new Exception();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		else
		{
			this.size=0;
			this.elementData=new Object[initialCapacity];
		}
	}		
	/**
	 * 获取ArrayList元素数量
	 * @return
	 */
	public int size()
	{
		return size;
	}	
	/**
	 * 判断当前ArrayList是否为空
	 * @return
	 */
	public boolean isEmpty()
	{
		return size==0;
	}		
	/**
	 * 查询指定下标的元素对象
	 * @param index
	 * @return
	 */
	public Object getIndex(int index)
	{	
		if(index>=0&&index<size)
		    return elementData[index];
		else
		{
			try
			{
				throw new ArrayIndexOutOfBoundsException();
			}
			catch(ArrayIndexOutOfBoundsException e)
			{
				e.printStackTrace();
			}
			return null;
		}			
	}	
	/**
	 * 队尾添加元素
	 * 1、先对容量进行确认,如果满了需要扩容
	 * 2、添加一个元素到队尾
	 * @param obj
	 * @return
	 */
	public boolean add(Object obj)
	{
		ensureCapacity();
		elementData[size]=obj;
		size++;
			return true;
	}	
	/**
	 * 指定下标添加
	 * 1、下标检查
	 * 2、数组容量检查
	 * 3、后移部分数据
	 * 4、插入数据
	 * @param index
	 * @param obj
	 */
	public void add(int index , Object obj)
	{
		rangeCheck(index);  
		ensureCapacity();
		System.arraycopy(elementData, index, elementData, index+1, size-index);
		elementData[index]=obj;
		size++;
	}	
	/**
	 * 删除指定下标的元素
	 * 1、下标检查
	 * 2、保存要删除的元素
	 * 3、部分前移覆盖
	 * 4、返回被删除的元素
	 * @param index
	 * @return
	 */
	public Object remove(int index)
	{
		rangeCheck(index);
		Object obj = elementData[index];
		System.arraycopy(elementData, index+1, elementData, index, size-index-1);
		size--;
		return obj;
	}	
	/**
	 * 删除指定元素
	 * 1、元素的位置
	 * 2、删除元素并返回true
	 * 3、查找失败返回false
	 * @param obj
	 * @return
	 */
	public boolean remove(Object obj)
	{
		for(int i=0;i<size;i++)
		{
			if(elementData[i].equals(obj))
			{
				System.arraycopy(elementData, i+1, elementData, i, size-i-1);
				size--;
				return true;
			}
		}
		return false;
	}	
	/**
	 * 设置指定下标的元素内容
	 * @param index
	 * @param obj
	 * @return
	 */
	public Object set(int index,Object obj)
	{
		rangeCheck(index);
		Object objReturn = elementData[index];
		elementData[index]=obj;
		return objReturn;
	}	
	/**
	 * 下标检查
	 */
	private void rangeCheck(int index) {
		// TODO Auto-generated method stub
		if(index<0||index>=size)
		{
			try
			{
				throw new ArrayIndexOutOfBoundsException();
			}
			catch(ArrayIndexOutOfBoundsException e)
			{
				e.printStackTrace();
			}
		}
	}
	/**
	 * 数组扩容判断方法
	 */
	private void ensureCapacity() {
		// TODO Auto-generated method stub
		if(size==elementData.length)
		{
			System.out.println("发生了扩容");
		     Object[] elementData = new Object[(int)((double)this.elementData.length*1.5)];
		     for(int i=0;i<size;i++)   //把之前数组的值都复制到新的数组
		     {
		    	 elementData[i] = this.elementData[i];
		     }
		     this.elementData=elementData;  //把新的数组定义为当前数组
		}
	}
	public static void main(String[] args)
	{
		MyArrayList ma = new MyArrayList();
		ma.add(1);   
		ma.add("ddd");
		ma.add(4);		
		int[] a =new int[100];  //创建一个对象的引用,用来作为一个测试元素
		ma.add(a);
		ma.add("sssss");
		ma.add("sd");
		ma.add("3445");
		ma.add("555");
		ma.add("736");
		ma.add(55);
		ma.add("nn");
		ma.add("456");
		ma.add("tt");
		ma.add(57);
		ma.add("ok");
		System.out.println("是否为空:"+ma.isEmpty());	
		System.out.println("队尾添加元素");
		for(int i=0;i<ma.size;i++)
			System.out.println(ma.getIndex(i));					
		ma.add(3, "123");
		System.out.println("在指定index=3位置添加元素123");
		for(int i=0;i<ma.size;i++)
			System.out.println(ma.getIndex(i));
		ma.remove(2);
		System.out.println("删除index=2位置的元素");
		for(int i=0;i<ma.size;i++)
			System.out.println(ma.getIndex(i));
		ma.remove(a);
		System.out.println("删除a对象");
		for(int i=0;i<ma.size;i++)
			System.out.println(ma.getIndex(i));
		ma.set(11, "888");
		System.out.println("设置index=11处字符串为888");
		for(int i=0;i<ma.size;i++)
			System.out.println(ma.getIndex(i));
		ma.remove(12);
		System.out.println("删除index=12的元素");
		for(int i=0;i<ma.size;i++)
			System.out.println(ma.getIndex(i));
	}
}

测试结果(测试所有方法,并使得元素数量超过10,测试扩容机制):

发生了扩容
是否为空:false
队尾添加元素
1
ddd
4
[I@15db9742
sssss
sd
3445
555
736
55
nn
456
tt
57
ok
发生了扩容
在指定index=3位置添加元素123
1
ddd
4
123
[I@15db9742
sssss
sd
3445
555
736
55
nn
456
tt
57
ok
删除index=2位置的元素
1
ddd
123
[I@15db9742
sssss
sd
3445
555
736
55
nn
456
tt
57
ok
删除a对象
1
ddd
123
sssss
sd
3445
555
736
55
nn
456
tt
57
ok
设置index=11处字符串为888
1
ddd
123
sssss
sd
3445
555
736
55
nn
456
888
57
ok
删除index=12的元素
1
ddd
123
sssss
sd
3445
555
736
55
nn
456
888
ok

猜你喜欢

转载自blog.csdn.net/mayifan_blog/article/details/85775840