最近有在温习一下java容器,今天就开始读一下ArrayList的动态扩容
ArrayList叫做动态数组,实现了长度可变的数组, 在内存中分配连续的空间.
优缺点
优点:
遍历元素和随机访问元素的效率较高
缺点:
添加和删除需要大量移动元素,效率低;按照内容查询效率低;
ArrayList是在object包中,继承于Collection与其子类AbstractList的.
所有实现了的接口有:Serializable(序列化), Cloneable(克隆), Iratable(迭代器),Collection(集合), List(列表),RandomAccess(随机存取)
三个初始化方法:
/**
* Constructs an empty list with an initial capacity of ten.
* (构造一个初始容量为10的空列表)
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*(为默认空实例提供的空的数组实例,用来区分EMPTY_ELEMENTDATA,以便了解当添加第一个元素时是如何扩容的)
*/
//简而言之就是个空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with the specified initial capacity.
*(用指定的初始容量构造一个空的列表)
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
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);
}
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
* (构造一个包含了该集合的列表,并按照集合的迭代器依次返回)
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
//将集合C中的内容转化为数组形式存放
elementData = c.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)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
这里这一段可能不易理解
// defend against c.toArray (incorrectly) not returning Object[] // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652) //elementData的对象不等于toArray()方法的运行时对象,保证了这个,再进行拷贝 //否则数组有可能发生错乱 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); ----------------------------------------------------------------------------------------------------------------------------------- /** toArray()方法 //简而言之意思就是:返回一个数组,这个数组是按照之前的顺序返回得到的 * Returns an array containing all of the elements in this collection. * If this collection makes any guarantees as to what order its elements * are returned by its iterator, this method must return the elements in * the same order. The returned array's {@linkplain Class#getComponentType * runtime component type} is {@code Object}. * //返回一个运行时组件类型为对象的数组,包含所有该集合中的元素 * @return an array, whose {@linkplain Class#getComponentType runtime component * type} is {@code Object}, containing all of the elements in this collection */ Object[] toArray();
容量的变化是先从创建开始的,然后添加元素,伴随着容量的变化;
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*(这个辅助方法是从add(E)方法分离而来的,为了保持方法字节码低于35,这将有助于add(E)方法调用C1编译循环)(至于咋优化的咱也不想知道)
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
/**
* Appends the specified element to the end of this list.
*(追加指定的元素到列表的末端)
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
modCount++;
//此处调用上面的那个方法
add(e, elementData, size);
return true;
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*(增加容量来保证至少能够容纳这些元素)
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
private Object[] grow() {
return grow(size + 1);
}
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by 50% if that suffices.
* Will not return a capacity greater than MAX_ARRAY_SIZE unless
* the given minimum capacity is greater than MAX_ARRAY_SIZE.
*(返回一个至少与给定的最小容量一样大的容量)
*(如果足够的话,返回增加当前容量增加50%的容量)
*(除非给定的(传参传进来的)最小容量比MAX_ARRAY_SIZE的值要大,不然不会返回一个比MAX_ARRAY_SIZE还大的值)
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//(oldCapacity >> 1)右移操作,右移一位,二进制数右移一位,左边补0;相当于除以二;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
//三元运算符,(判断表达式)? A : B;加入判断表达式得出为true,则返回A,否则返回B
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
再贴出hugeCapacity()方法
//无需多言,相信大家都看的懂
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 class test {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
System.out.println(getArrayListCapacity(arrayList));
for (int i = 0; i < 5; i++) {
arrayList.add(i);
for (int j = 0; j < 5; j++) {
arrayList.add(j);
//想看到更多的容量值变换,可以将i,j的值变大,并在循环体打印
// System.out.println(getArrayListCapacity(arrayList));
}
System.out.println(getArrayListCapacity(arrayList));
}
}
//利用反射机制获取当前ArrayList对象的容量
public static int getArrayListCapacity(ArrayList arrayList) {
Class<ArrayList> arrayListClass = ArrayList.class;
try {
Field field = arrayListClass.getDeclaredField("elementData");
field.setAccessible(true);
Object[] objects = (Object[])field.get(arrayList);
return objects.length;
} catch (NoSuchFieldException e) {
e.printStackTrace();
return -1;
} catch (IllegalAccessException e) {
e.printStackTrace();
return -1;
}
}
}
输出内容
结果也是十分清晰:
创建时为0,然后马上给了10的容量值,当容量到达了10后,再次添加到10的1.5倍,一直如此,这就是ArrayList的动态扩容了.