JAVA集合框架5---ArrayList源码解析

ArrayList是一个动态数组容器,实现了List接口的所有方法,并且可以容纳null,和C++中的vector一样。底层用一个数组来组织数据,所有的方法都是围绕着这个数组进行的。除此之外,ArrayList还提供了两个公有API来对数组大小的操作,分别是trimToSize与ensureCapacity。ArrayList是我们平常使用比较多的一个集合类,掌握它的源码有助于我们更好的使用它。

ArrayList源码如下:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    //AbstractList 与 List 的源码与关系在之前的文章中已经分析过了。
    //RandomAccess是随机访问接口,可以在O(1)时间内根据所以返回元素。
    //Cloneable表示可以被克隆(这个拷贝是浅拷贝)。序列化接口Serializable。
    private static final long serialVersionUID = 8683452581122892189L;
    //默认数组的容量大小
    private static final int DEFAULT_CAPACITY = 10;
    //空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
    //通过无参构造器,也即 new ArrayList<>(),生成对象时的默认空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    // 以下两个成员变量 elementData与size是ArrayList最主要的两个变量,所有的方法都是围绕着它们两
    //储存元素的数组
    transient Object[] elementData;
    //集合元素的大小
    private int size;
    
    //构造函数
    //给elementData数组一个初始大小
    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;
    }
    //通过其它集合来初始化elementData
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray(); // toArray 集合与数组之间的转化桥梁
        if ((size = elementData.length) != 0) {
            // defend against c.toArray (incorrectly) not returning Object[]
            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
            if (elementData.getClass() != Object[].class) // 意思是如果 toArray 返回类型不是 Object[] ,那么在重新复制一份
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
}

 分析完构造函数之后,下面分析两个对数组elementData大小直接操作的两个函数

//缩减elementData数组的大小,使其刚好等于集合大小
public void trimToSize() {
	modCount++; // modCount 继承自AbstractList
	if (size < elementData.length) {
		elementData = (size == 0)
		  ? EMPTY_ELEMENTDATA
		  : Arrays.copyOf(elementData, size);
	}
}
//确保elementData的大小至少为minCapacity.这个函数是给外界调用的,在ArrayList里面并没有使用到这个函数
public void ensureCapacity(int minCapacity) {
	if (minCapacity > elementData.length
		&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
			 && minCapacity <= DEFAULT_CAPACITY)) {  // 当ArrayList对象是通过无参构造函数创建且minCapacity小于等于DEFAULT_CAPACITY(10)时,什么也不做。
		modCount++;
		grow(minCapacity);
	}
}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private Object[] grow(int minCapacity) {
	return elementData = Arrays.copyOf(elementData,newCapacity(minCapacity));
}

private Object[] grow() {
	return grow(size + 1);
}
private int newCapacity(int minCapacity) {
	// overflow-conscious code
	int oldCapacity = elementData.length;
	int newCapacity = oldCapacity + (oldCapacity >> 1);  //每次扩容1.5倍
	if (newCapacity - minCapacity <= 0) {
		if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
			return Math.max(DEFAULT_CAPACITY, minCapacity);
		if (minCapacity < 0) // overflow
			throw new OutOfMemoryError();
		return minCapacity;
	}
	return (newCapacity - MAX_ARRAY_SIZE <= 0)
		? newCapacity
		: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
	if (minCapacity < 0) // overflow
		throw new OutOfMemoryError();
	return (minCapacity > MAX_ARRAY_SIZE)
		? Integer.MAX_VALUE
		: MAX_ARRAY_SIZE;
}

查询操作源码:

// 返回长度
public int size() {
	return size;
}
//判断是否为空
public boolean isEmpty() {
	return size == 0;
}
//判断是否包含对象o
public boolean contains(Object o) {
	return indexOf(o) >= 0;
}
//返回对象o的索引,不存在就返回-1
public int indexOf(Object o) {
	return indexOfRange(o, 0, size);
}
int indexOfRange(Object o, int start, int end) {
	Object[] es = elementData;
	if (o == null) {
		for (int i = start; i < end; i++) {
			if (es[i] == null) {
				return i;
			}
		}
	} else {
		for (int i = start; i < end; i++) {
			if (o.equals(es[i])) {
				return i;
			}
		}
	}
	return -1;
}
public int lastIndexOf(Object o) {
	return lastIndexOfRange(o, 0, size);
}
int lastIndexOfRange(Object o, int start, int end) {
	Object[] es = elementData;
	if (o == null) {
		for (int i = end - 1; i >= start; i--) {
			if (es[i] == null) {
				return i;
			}
		}
	} else {
		for (int i = end - 1; i >= start; i--) {
			if (o.equals(es[i])) {
				return i;
			}
		}
	}
	return -1;
}
E elementData(int index) {
	return (E) elementData[index];
}
public E get(int index) {
	Objects.checkIndex(index, size); //检测输入是否合法
	return elementData(index);
}

修改操作:

//更改指定索引处的元素
public E set(int index, E element) {
	Objects.checkIndex(index, size);
	E oldValue = elementData(index);
	elementData[index] = element;
	return oldValue;
}
private void add(E e, Object[] elementData, int s) {
	if (s == elementData.length)
		elementData = grow();  // 如果索引s等于elementData数组的容量,扩容
	elementData[s] = e;  // 插入
	size = s + 1;  // 更新size
}
// 添加元素到末尾
public boolean add(E e) {
	modCount++;
	add(e, elementData, size);
	return true;
}
// 在指定索引处插入元素
public void add(int index, E element) {
	rangeCheckForAdd(index);
	modCount++;
	final int s;
	Object[] elementData;
	if ((s = size) == (elementData = this.elementData).length)
		elementData = grow();
	System.arraycopy(elementData, index,elementData, index + 1,s - index);  // index处之后的元素向后移一位,为新插入的元素腾空间
	elementData[index] = element;
	size = s + 1;
}
//根据索引删除元素,返回删除的元素
public E remove(int index) {
	Objects.checkIndex(index, size);
	final Object[] es = elementData;

	@SuppressWarnings("unchecked") E oldValue = (E) es[index];
	fastRemove(es, index);

	return oldValue;
}
//根据对象删除元素
public boolean remove(Object o) {
	final Object[] es = elementData;
	final int size = this.size;
	int i = 0;
	found: {
		if (o == null) {
			for (; i < size; i++)
				if (es[i] == null)
					break found;  // 带标签的break语法
		} else {
			for (; i < size; i++)
				if (o.equals(es[i]))
					break found;
		}
		return false;
	}
	fastRemove(es, i);
	return true;
}
private void fastRemove(Object[] es, int i) {
	modCount++;
	final int newSize;
	if ((newSize = size - 1) > i)
		System.arraycopy(es, i + 1, es, i, newSize - i);
	es[size = newSize] = null;
}
public void clear() {
	modCount++;
	final Object[] es = elementData;
	for (int to = size, i = size = 0; i < to; i++)
		es[i] = null;
}

批量修改操作源码:

// 添加集合c中的所有元素到末尾
public boolean addAll(Collection<? extends E> c) {
	Object[] a = c.toArray();
	modCount++;
	int numNew = a.length;
	if (numNew == 0)
		return false;
	Object[] elementData;
	final int s;
	if (numNew > (elementData = this.elementData).length - (s = size))  // 判断数组elementData能否容纳集合c中的所有元素,不能就扩容
		elementData = grow(s + numNew);
	System.arraycopy(a, 0, elementData, s, numNew);
	size = s + numNew;
	return true;
}
//在指定位置添加集合c中的所有元素
public boolean addAll(int index, Collection<? extends E> c) {
	rangeCheckForAdd(index); // 检测index是否合法

	Object[] a = c.toArray();
	modCount++;
	int numNew = a.length;
	if (numNew == 0)
		return false;
	Object[] elementData;
	final int s;
	if (numNew > (elementData = this.elementData).length - (s = size))
		elementData = grow(s + numNew);

	int numMoved = s - index;
	if (numMoved > 0)
		System.arraycopy(elementData, index,elementData, index + numNew,numMoved); //将index之后的元素向后移
	System.arraycopy(a, 0, elementData, index, numNew);
	size = s + numNew;
	return true;
}
// 删除集合c中的所有元素
public boolean removeAll(Collection<?> c) {
	return batchRemove(c, false, 0, size);
}
// 保留那些集合c与elementData都有的元素
public boolean retainAll(Collection<?> c) {
	return batchRemove(c, true, 0, size);
}

boolean batchRemove(Collection<?> c, boolean complement,
					final int from, final int end) {
	Objects.requireNonNull(c); // 确保集合c不为null
	final Object[] es = elementData;
	int r;
	// Optimize for initial run of survivors
    // 优化初始位置
	for (r = from;; r++) {
		if (r == end)
			return false;
		if (c.contains(es[r]) != complement)
			break;
	}
    // 其实就是两层for循环,时间复杂度为O(n^2)。contains是线性搜索,时间复杂度为O(n)
	int w = r++;
	try {
		for (Object e; r < end; r++)
			if (c.contains(e = es[r]) == complement)
				es[w++] = e;
	} catch (Throwable ex) {
		// Preserve behavioral compatibility with AbstractCollection,
		// even if c.contains() throws.
		System.arraycopy(es, r, es, w, end - r);
		w += end - r;
		throw ex;
	} finally {
		modCount += end - w;
		shiftTailOverGap(es, w, end);
	}
	return true;
}
// 将从索引hi开始的元素移到从lo开始,也就是抹掉lo---hi 之间的元素 (左闭右开)
private void shiftTailOverGap(Object[] es, int lo, int hi) {
	System.arraycopy(es, hi, es, lo, size - hi);
	for (int to = size, i = (size -= hi - lo); i < to; i++)
		es[i] = null;
}

重写Object类的源码:(比较简单,直接看就明白了)

public boolean equals(Object o) {
	if (o == this) {
		return true;
	}

	if (!(o instanceof List)) {
		return false;
	}

	final int expectedModCount = modCount;
	// ArrayList can be subclassed and given arbitrary behavior, but we can
	// still deal with the common case where o is ArrayList precisely
	boolean equal = (o.getClass() == ArrayList.class)
		? equalsArrayList((ArrayList<?>) o)
		: equalsRange((List<?>) o, 0, size);

	checkForComodification(expectedModCount);
	return equal;
}
boolean equalsRange(List<?> other, int from, int to) {
	final Object[] es = elementData;
	if (to > es.length) {
		throw new ConcurrentModificationException();
	}
	var oit = other.iterator();
	for (; from < to; from++) {
		if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) {
			return false;
		}
	}
	return !oit.hasNext();
}
private boolean equalsArrayList(ArrayList<?> other) {
	final int otherModCount = other.modCount;
	final int s = size;
	boolean equal;
	if (equal = (s == other.size)) {
		final Object[] otherEs = other.elementData;
		final Object[] es = elementData;
		if (s > es.length || s > otherEs.length) {
			throw new ConcurrentModificationException();
		}
		for (int i = 0; i < s; i++) {
			if (!Objects.equals(es[i], otherEs[i])) {
				equal = false;
				break;
			}
		}
	}
	other.checkForComodification(otherModCount);
	return equal;
}

private void checkForComodification(final int expectedModCount) {
	if (modCount != expectedModCount) {
		throw new ConcurrentModificationException();
	}
}
public int hashCode() {
	int expectedModCount = modCount;
	int hash = hashCodeRange(0, size);
	checkForComodification(expectedModCount);
	return hash;
}
int hashCodeRange(int from, int to) {
	final Object[] es = elementData;
	if (to > es.length) {
		throw new ConcurrentModificationException();
	}
	int hashCode = 1;
	for (int i = from; i < to; i++) {
		Object e = es[i];
		hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
	}
	return hashCode;
}

迭代器Iterator与listIterator的实现类与上一篇的实现几乎是一样的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
好的,让我们来一起编写一个随机点名的小程序,使用到泛型和集合框架。 首先,我们需要定义一个学生类,包含学生的姓名和学号: ```java public class Student { private String name; private String id; public Student(String name, String id) { this.name = name; this.id = id; } public String getName() { return name; } public String getId() { return id; } } ``` 接下来,我们可以使用一个泛型类来表示班级,其中包含了所有的学生对象: ```java import java.util.ArrayList; import java.util.List; import java.util.Random; public class Class<T extends Student> { private List<T> students; public Class() { students = new ArrayList<>(); } public void addStudent(T student) { students.add(student); } public T getRandomStudent() { Random random = new Random(); int index = random.nextInt(students.size()); return students.get(index); } } ``` 在这个泛型类中,我们使用了一个 ArrayList 来保存所有的学生对象,然后通过 getRandomStudent 方法随机返回一个学生对象。 最后,我们可以编写一个测试类来模拟随机点名的过程: ```java public class Test { public static void main(String[] args) { Class<Student> class1 = new Class<>(); class1.addStudent(new Student("张三", "001")); class1.addStudent(new Student("李四", "002")); class1.addStudent(new Student("王五", "003")); System.out.println("随机点名结果:"); Student student = class1.getRandomStudent(); System.out.println(student.getName() + " " + student.getId()); } } ``` 在这个测试类中,我们创建了一个班级对象 class1,并添加了三个学生对象。然后通过调用 getRandomStudent 方法随机返回一个学生对象,并输出其姓名和学号。 这就是一个简单的随机点名小程序,使用了泛型和集合框架来实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值