ArrayList源码

   ArrayList在编程中是比较常用的一个集合,ArrayList类是一个特殊的数组,通过添加和删除元素,就可以动态改变数组的长度。

public class ArrayList<E>extends AbstractList<E>
      implements List<E>, RandomAccess, Cloneable, Serializable

    ArrayList继承了AbstractList类,实现了List。即:具有了添加,删除,修改,遍历等功能。
    ArrayList实现了RandomAccess接口,即:能通过元素的序号快速访问对象。
    ArrayList实现了Cloneable接口,即:能被克隆。
    ArrayList实现了Serializable接口,即:支持序列化,能通过序列化传输。

// ArrayList带容量大小的构造函数。
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        // 新建一个数组
        this.elementData = new Object[initialCapacity];
    }
    // ArrayList构造函数。默认容量是10。
    public ArrayList() {
        this(10);
    }
    // 创建一个包含collection的ArrayList
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }
 
	// 若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2+1”
    public void ensureCapacity(int minCapacity) {
       // 将“修改统计数”+1
        modCount++;
        int oldCapacity = elementData.length;
      // 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;
            int newCapacity = (oldCapacity * 3)/2 + 1;
            if (newCapacity < minCapacity)
                newCapacity = minCapacity;
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    }

     通过构造函数可以看出,在使用ArrayList时,如果不设定初始容量的,ArrayList默认容量为10,因为ArrayList是动态数组,所以当容量不够时,ArryList会自动扩容的。自动扩容分两种情况,假设原来数组容量为10,并且已经有5个容量应经占用了,现在有要想数组中添加20 个元素。这时就需要考虑了,ArrayList扩容一次的容量为10x3/2+1=16,  16<20。说明扩容后的容量还是小于当前要添加的元素的个数,所以,ArrayList 直接将元素的个数当成现在要扩容的容量。也就是说,现在ArrayList的容量为30。
    所以ArrayList 扩容分两种情况:
    第一种:当要添加的元素个数,小于ArrayList扩容后容量时,Arraylist容量="(原始容量x3)/2+1"。
    第二种:当添加的元素个数,大于ArrayList扩容后的容量时,ArrayList容量=当前容量+元素的个数。

 ArrayList线程不安全,为什么说ArrayList线程不安全呢?

假设:
    在 Items[Size]的位置存放此元素;
    增大 Size 的值。
    在单线程运行的情况下,如果 Size= 0,添加一个元素后,此元素在位置 0,而且 Size=1;
    如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList添加元素,因为此时 Size 仍然等于 0(注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size的值。

        public static void main(String[] args) throws InterruptedException {
	        ThreadGroup group = new ThreadGroup("testgroup");
	        ArrayListInThread t = new ArrayListInThread();
	        for (int i = 0; i < 10000; i++) {
	            Thread th = new Thread(group, t, String.valueOf(i));
	            th.start();
	        }
	       
	        while (group.activeCount() > 0) {
	            Thread.sleep(10);
	        }
	        System.out.println();
            // it should be 10000 if thread safe collection is used.
	        System.out.println(t.list1.size()); 
	    }
		
		public class ArrayListInThread implements Runnable {
		 
			List<String> list1 = new ArrayList<String>(1);// not thread safe
		 
			// List<String> list1 = Collections.synchronizedList(new
			// ArrayList<String>());// thread safe
			public void run() {
				try {
					Thread.sleep((int) (Math.random() * 2));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				list1.add(Thread.currentThread().getName());
		 
			}
		 
		}

总结
    1.ArrayList是一个线程不安全的集合
     2.ArrayList因为是一个有序的集合,通过元素序号可以快速访问。但是在增删时比较慢。因为需要移动元素位置。
    3.ArrayList是一个动态的数组,她的扩容方式分两种情况。
      第一种:当要添加的元素个数,小于ArrayList扩容后容量时,Arraylist容量="(原始容量x3)/2+1"。
      第二种:当添加的元素个数,大于ArrayList扩容后的容量时,ArrayList容量=当前容量+元素的个数。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值