前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java集合-ArrayList源码

Java集合-ArrayList源码

作者头像
才疏学浅的木子
发布2023-10-17 08:37:21
1730
发布2023-10-17 08:37:21
举报
文章被收录于专栏:CSDN文章

参数

代码语言:javascript
复制
	//默认初始容量
	private static final int DEFAULT_CAPACITY = 10;
	//空数组(用于空实例)
    private static final Object[] EMPTY_ELEMENTDATA = {};
	//用于默认大小空实例的共享空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
	//保存数据的数组
    transient Object[] elementData; // non-private to simplify nested class access
	//元素个数
    private int size;

注意:这里有两个空数组,第一个空数组是容量为0的时候的数组,第二个空数组是使用空参构造器的时候的数组

构造方法

代码语言:javascript
复制
	//带有参数的构造器

	public ArrayList(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);
        }
    }
	
	//这就是与上面不一样的地方
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

扩容方法

如果有必要增加此ArrayList实例的容量以确保它至少能容纳元素的数量

代码语言:javascript
复制
	public void ensureCapacity(int minCapacity) {
		
		//这里就开始判处出前面两个空数组的区别了
		//如果这个list是无参构造的化没那么minExpand就为10,否则为0
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            ? 
            : DEFAULT_CAPACITY;
		//如果最小容量大于已有的最大容量
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

如果最小所需容量大于了实际可存储容量那么就需要扩容

判断是否真的需要扩容

代码语言:javascript
复制
   private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

这里就是扩容的具体办法其中分为几个情况

最开始新容量等于旧容量的1.5倍

  1. 新容量大等于最小所需容量,那么最后的新容量就等于旧容量的1.5倍
  2. 新容量小于最小所需容量,那么最后的新容量就等于最小所需容量
  3. 新容量大于List中规定最大容量,判断最小所需容量是否大于了List中规定的最小容量,如果没有则新容量还是等于最小容量,如果大于了则新容量等于Integer的最大值
代码语言:javascript
复制
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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:
        elementData = Arrays.copyOf(elementData, 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;
    }
代码语言:javascript
复制
 	private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

计算最小容量是否会等于10

代码语言:javascript
复制
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

增删改查方法

增删改查的方法都是十分简单的所以不过多赘述

但是要注意在增加和删除方法的每一次调用的时候都会使modCount++

Iterator迭代器

在ArrayList内部有个Itr的内部类

代码语言:javascript
复制
private class Itr implements Iterator<E> {
		//当前游标位置
        int cursor; 
        //上一个游标位置
        int lastRet = -1; 
        //修改次数
        int expectedModCount = modCount;

        Itr() {}
		
		//是否还存在下一个
        public boolean hasNext() {
            return cursor != size;
        }
        
        @SuppressWarnings("unchecked")
        public E next() {
        
        	//检查期待修改次数与实际的修改次数是否发生变化
        	//如果有变化就抛出异常
            checkForComodification();
            
            int i = cursor;
            
            if (i >= size) //判断是否越界
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            
            if (i >= elementData.length) //判断是否越界
                throw new ConcurrentModificationException();
            
            cursor = i + 1; //游标变为下一个
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

快速失败

前面都说了modCount属性,然后迭代器哪里也使用到了所以这里就说一下它的作用,它的作用就是实现快速失败,每次迭代器遍历的时候都会去查询实际的modCount属性与迭代器中保存的modCount属性是否相同,如果不同那么就抛出异常,这就是快速失败

拓展:安全失败:安全失败使用的写时复制技术,这个迭代器中遍历的数据是复制的数据,所以对于原有数据的修改不会影响到复制的数据

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 参数
  • 构造方法
  • 扩容方法
  • 增删改查方法
  • Iterator迭代器
  • 快速失败
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档