ArrayList集合源码解读

引言:最近帮其它部门面试了几位java开发人员,简历上写的都是3/4年开发经验,经过面试下来发现他们所体现出来的技术深度和广度最多均在1.5年以内,具体有多少包装成分也不去深究,我面试是一定会问到集合的,由浅至深,基本套路就是:你最常用的集合有哪些(大部分人应该都是ArrayList和HashMap吧)?说说你对ArrayList的理解?平时使用ArrayList遇到过什么问题?ArrayList的扩容过程?能否现场写一个ArrayList实现?包括HashMap也是这样问的。却发现ArrayList作为最简单集合之一,还是很多人说不清楚。此篇博文只是随便写写,只当是温习一下ArrayList源码吧。


ArrayList特点:查询快、有序、自动扩容、元素可为空,源码解读从构造方法开始:ArrayList支持三种构造方式:

 
 //初始化指定集合大小
 public ArrayList(int var1) {
     if (var1 > 0) {
         this.elementData = new Object[var1];
     } else {
           
         //集合大小不能小于0
         if (var1 != 0) {
             throw new IllegalArgumentException("Illegal Capacity: " + var1);
         }
         this.elementData = EMPTY_ELEMENTDATA;
     }
}
//不指定集合大小,默认为空数组
public ArrayList() {
     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//初始化指定某个集合,将形参集合传递给ArrayList的数组
public ArrayList(Collection var1) {
        this.elementData = var1.toArray();
        if ((this.size = this.elementData.length) != 0) {
            if (this.elementData.getClass() != Object[].class) {
                this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
            }
        } else {
            this.elementData = EMPTY_ELEMENTDATA;
        }
}

接着就是ArrayList常见的几个方法:获取集合大小、集合是否为空、是否包含某元素、转换为数组,都很简单:

public int size() {
	return this.size;
}

public boolean isEmpty() {
	return this.size == 0;
}

public boolean contains(Object var1) {
	return this.indexOf(var1) >= 0;
}

public int indexOf(Object var1) {
	int var2;
	if (var1 == null) {
		for(var2 = 0; var2 < this.size; ++var2) {
			if (this.elementData[var2] == null) {
				return var2;
			}
		}
	} else {
		for(var2 = 0; var2 < this.size; ++var2) {
			if (var1.equals(this.elementData[var2])) {
				return var2;
			}
		}
	}

	return -1;
}

public Object[] toArray() {
    return Arrays.copyOf(this.elementData, this.size);
}

再接下来就是get获取元素方法了,get方法里面做了两个事情,先检查数组下标是否越界,越界直接抛异常,否则根据下标从数组中获取元素:

public E get(int var1) {
	this.rangeCheck(var1);
	return this.elementData(var1);
}

private void rangeCheck(int var1) {
   if (var1 >= this.size) {
	   throw new IndexOutOfBoundsException(this.outOfBoundsMsg(var1));
   }
}

接着是add方法,add方法里做了两个事:若为空数组,则初始化为大小为10,再确定数组的容量是否需要扩容,扩容为(原容量+原容量/2),接着在数组的(size+1)位置上放入新增的元素:

public boolean add(E var1) {
	this.ensureCapacityInternal(this.size + 1);
	this.elementData[this.size++] = var1;
	return true;
}

private void ensureCapacityInternal(int var1) {
	//注意空数组的特殊情况,将数组大小赋为10了
	if (this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		var1 = Math.max(10, var1);
	}

	this.ensureExplicitCapacity(var1);
}

private void ensureExplicitCapacity(int var1) {
        //modCount防止并发修改
	++this.modCount;
	//这个地方要注意:this.elementData在第一次add时候大小赋值为了10
	if (var1 - this.elementData.length > 0) {
		this.grow(var1);
	}

}

private void grow(int var1) {
	int var2 = this.elementData.length;
	//扩容为(原容量+原容量/2)
	int var3 = var2 + (var2 >> 1);
	if (var3 - var1 < 0) {
		var3 = var1;
	}

	if (var3 - 2147483639 > 0) {
		var3 = hugeCapacity(var1);
	}

	this.elementData = Arrays.copyOf(this.elementData, var3);
}

private static int hugeCapacity(int var0) {
	if (var0 < 0) {
		throw new OutOfMemoryError();
	} else {
		return var0 > 2147483639 ? 2147483647 : 2147483639;
	}
}

以上便是ArrayList的核心代码了,比较简单,如果别人面试时让你实现一个ArrayList,可千万别说不会,会被看扁的~

后面有空再补充一些吧~

你可能感兴趣的:(Java,Java编程之路)