Java源码学习--ArrayList源码解析
2016-08-01 02:23
567 查看
ArrayList类中全局变量的意义
ArrayList的构造方法
创建一个ArrayList对象,不带参数的时候 是创建了一个长度为10的Object数组 带int类型参数的时候就是创建指定长度的Object数组 带Collection类型的构造方法,指明该ArrayList是什么类型的数组
常用的方法
1). Arrays.copyOf(T[] original, int newLength) 此方法是创建一个新数组返回,并且将原有数组中的值复制到新数组中
2). System.arraycopy(Object src, int srcPos,Object dest, int destPos, int length); 该方法被标记了native,调用了系统的C/C++代码,在JDK中是看不到的,但在openJDK中可以看到其源码。该函数实际上最终调用了C语言的memmove()函数,因此它可以保证同一个数组内元素的正确复制和移动,比一般的复制方法的实现效率要高很多,很适合用来批量处理数组。Java强烈推荐在复制大量数组元素时用该方法,以取得更高的效率。 方法的参数的含义
第一个是要复制的数组,第二个是从要复制的数组的第几个开始,第三个是复制到那,四个是复制到的数组第几个开始,最后一个是复制长度
trimToSize()方法
此方法是将数组中的元素个数做为数组的长度生成一个新的数组,并将新数组内存地址指向当前集合,将多余的空间释放
size()方法
int返回值 返回数组中元素的个数
isEmpty()方法
boolean返回值,返回当前数组的的个数是否等于0 等于0为true 否则为false
contains(Object o)方法
boolean返回值 此方法的原理是调用indexOf(Object o)之后判断返回值是否>=0,具体的后面将indexOf时详细讲解
indexOf(Object o)方法 正序比较
int返回值 此方法是将数组中的每个元素都取出来与传入的对象进行对比,如果相等就返回对象所在下标,否则返回-1
lastIndexOf(Object o)方法 倒序比较
int返回值 实现原理跟indexOf一样,只是一个是从前到后的比较,一个是从后到前的比较
clone()方法
Object返回值 官方解释“浅表复制”,我的理解就是创建一个List对象,但是对象内的元素内存指向没变,也就是说但修改这个集合中元素时,另一个集合中的元素也会发生变化
,也就是List集合对象,通过创建一个ArrayList 集合来接收数组
toArray()方法
Object[] 返回值,此方法就是将底层存放的数组复制一个返回回去
toArray(T[] a)方法
Object[] 返回值,如果传入数组长度比当前集合中元素个数小,则创建一个新的数组返回,大小为集合中元素的个数,类型为传入数组的类型
传入数组长度等于集合中元素个数 则将集合中的值复制进入则返回传入数组,并返回传入数组
如果长度大于元素数组个数 除复制集合外 还将传入数组的第size个数组置为空
get(int index)方法
Object 返回值 此方法先验证传入的下标是否在数组中,如果存在则返回对应下标的值,否则则跑出异常
set(int index, E element)方法
Object返回值,修改指定下标的值,并且将原来的值返回回来
add(E e)方法 插入数组最后一位
当传入的一个参数的时候 先调用ensureCapacityInternal()方法,ensureCapacityInternal是判断底层生成的那个Object数组是否越界,如果越界,则新生成一个数组,并存入值,否则则将值存入数组中
判断规则为 原来值的长度的1.5倍比传入的值大则创建一个新的数组,数组长度为原来的1.5倍,如果小的话 就创建一个长度为传入参数的数组,最后还有个判断是判断数组最大长度,如果新生成的那个数组长度值比系统定义的数组最大长度还大,那么将创建一个数组,此数组长度为系统默认的最大长度
ArrayList add(int index, E element) 指定插入位置
先验证要插入的位置是否在数组中,然后用跟上面原理一样的方式创建一个新数组,并且新数组,然后调用系统最底层方法System.arraycopy复制一个数组出来,将当前值存入复制出来的集合中的index位置,因为这里多了一个元素,所以要将AarrayList中的size+1
remove(int index)方法 删除指定下标的元素
Object 返回值 先验证下标是否可用,然后得到当前对象,得到System.arraycopy要复制长度的值,因为下面是要从传入数组的下一个值开始复制,因此这里要减1否则取值时要越界,因为原有的值从新数组中删除,所以原有的值后面所有值都会前进一位,导致数组最后一位无值,因此需要将最后一位赋值为空
remove(Object o)方法 根据对象删除集合中元素
boolean 返回值 判断传入的对象是否在数组中,存在则执行remove(int index)的原理,并返回true,否则返回false
clear()方法
此方法为情况当前集合,也就是清空数组,但需要注意的是,该方法不会改变数组的长度,只会将数组的值赋为空
注意事项
集合当中只能放置对象的引用,无法放置原生数据类型,我们需要使用原生数据类型的包装类才能加入到集合当中;
集合当中放置的都是Object类型,因此取出来的也是Object类型,那么我们必须要使用强制类型转换将其转换为真正的类型(放置进去的类型);
总结
通过阅读ArrayList的源码才知道,原来ArrayList的底层是用数组实现的,并且add方法是用创建数组的方式来增长边界的。
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. */ private transient Object[] elementData; //存放值的数组
/** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size; //数组中元素的个数
/** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //数组的临界点-8
ArrayList的构造方法
创建一个ArrayList对象,不带参数的时候 是创建了一个长度为10的Object数组 带int类型参数的时候就是创建指定长度的Object数组 带Collection类型的构造方法,指明该ArrayList是什么类型的数组
/** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this(10); }
/** * 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) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[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) { 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); }
常用的方法
1). Arrays.copyOf(T[] original, int newLength) 此方法是创建一个新数组返回,并且将原有数组中的值复制到新数组中
public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); } public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
2). System.arraycopy(Object src, int srcPos,Object dest, int destPos, int length); 该方法被标记了native,调用了系统的C/C++代码,在JDK中是看不到的,但在openJDK中可以看到其源码。该函数实际上最终调用了C语言的memmove()函数,因此它可以保证同一个数组内元素的正确复制和移动,比一般的复制方法的实现效率要高很多,很适合用来批量处理数组。Java强烈推荐在复制大量数组元素时用该方法,以取得更高的效率。 方法的参数的含义
第一个是要复制的数组,第二个是从要复制的数组的第几个开始,第三个是复制到那,四个是复制到的数组第几个开始,最后一个是复制长度
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
trimToSize()方法
此方法是将数组中的元素个数做为数组的长度生成一个新的数组,并将新数组内存地址指向当前集合,将多余的空间释放
/** * Trims the capacity of this <tt>ArrayList</tt> instance to be the * list's current size. An application can use this operation to minimize * the storage of an <tt>ArrayList</tt> instance. */ public void trimToSize() { modCount++; int oldCapacity = elementData.length; if (size < oldCapacity) { elementData = Arrays.copyOf(elementData, size); } }
size()方法
int返回值 返回数组中元素的个数
/** * Returns the number of elements in this list. * * @return the number of elements in this list */ public int size() { return size; }
isEmpty()方法
boolean返回值,返回当前数组的的个数是否等于0 等于0为true 否则为false
/** * Returns <tt>true</tt> if this list contains no elements. * * @return <tt>true</tt> if this list contains no elements */ public boolean isEmpty() { return size == 0; }
contains(Object o)方法
boolean返回值 此方法的原理是调用indexOf(Object o)之后判断返回值是否>=0,具体的后面将indexOf时详细讲解
/** * Returns <tt>true</tt> if this list contains the specified element. * More formally, returns <tt>true</tt> if and only if this list contains * at least one element <tt>e</tt> such that * <tt>(o==null ? e==null : o.equals(e))</tt>. * * @param o element whose presence in this list is to be tested * @return <tt>true</tt> if this list contains the specified element */ public boolean contains(Object o) { return indexOf(o) >= 0; }
indexOf(Object o)方法 正序比较
int返回值 此方法是将数组中的每个元素都取出来与传入的对象进行对比,如果相等就返回对象所在下标,否则返回-1
/** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the lowest index <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
lastIndexOf(Object o)方法 倒序比较
int返回值 实现原理跟indexOf一样,只是一个是从前到后的比较,一个是从后到前的比较
/** * Returns the index of the last occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the highest index <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. */ public int lastIndexOf(Object o) { if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; }
clone()方法
Object返回值 官方解释“浅表复制”,我的理解就是创建一个List对象,但是对象内的元素内存指向没变,也就是说但修改这个集合中元素时,另一个集合中的元素也会发生变化
,也就是List集合对象,通过创建一个ArrayList 集合来接收数组
/** * Returns a shallow copy of this <tt>ArrayList</tt> instance. (The * elements themselves are not copied.) * * @return a clone of this <tt>ArrayList</tt> instance */ public Object clone() { try { @SuppressWarnings("unchecked") ArrayList<E> v = (ArrayList<E>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } }
toArray()方法
Object[] 返回值,此方法就是将底层存放的数组复制一个返回回去
/** * Returns an array containing all of the elements in this list * in proper sequence (from first to last element). * * <p>The returned array will be "safe" in that no references to it are * maintained by this list. (In other words, this method must allocate * a new array). The caller is thus free to modify the returned array. * * <p>This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this list in * proper sequence */ public Object[] toArray() { return Arrays.copyOf(elementData, size); }
toArray(T[] a)方法
Object[] 返回值,如果传入数组长度比当前集合中元素个数小,则创建一个新的数组返回,大小为集合中元素的个数,类型为传入数组的类型
传入数组长度等于集合中元素个数 则将集合中的值复制进入则返回传入数组,并返回传入数组
如果长度大于元素数组个数 除复制集合外 还将传入数组的第size个数组置为空
/** * Returns an array containing all of the elements in this list in proper * sequence (from first to last element); the runtime type of the returned * array is that of the specified array. If the list fits in the * specified array, it is returned therein. Otherwise, a new array is * allocated with the runtime type of the specified array and the size of * this list. * * <p>If the list fits in the specified array with room to spare * (i.e., the array has more elements than the list), the element in * the array immediately following the end of the collection is set to * <tt>null</tt>. (This is useful in determining the length of the * list <i>only</i> if the caller knows that the list does not contain * any null elements.) * * @param a the array into which the elements of the list are to * be stored, if it is big enough; otherwise, a new array of the * same runtime type is allocated for this purpose. * @return an array containing the elements of the list * @throws ArrayStoreException if the runtime type of the specified array * is not a supertype of the runtime type of every element in * this list * @throws NullPointerException if the specified array is null */ @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
get(int index)方法
Object 返回值 此方法先验证传入的下标是否在数组中,如果存在则返回对应下标的值,否则则跑出异常
/** * Checks if the given index is in range. If not, throws an appropriate * runtime exception. This method does *not* check if the index is * negative: It is always used immediately prior to an array access, * which throws an ArrayIndexOutOfBoundsException if index is negative. */ private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { rangeCheck(index); return elementData(index); }
set(int index, E element)方法
Object返回值,修改指定下标的值,并且将原来的值返回回来
/** * Replaces the element at the specified position in this list with * the specified element. * * @param index index of the element to replace * @param element element to be stored at the specified position * @return the element previously at the specified position * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
add(E e)方法 插入数组最后一位
当传入的一个参数的时候 先调用ensureCapacityInternal()方法,ensureCapacityInternal是判断底层生成的那个Object数组是否越界,如果越界,则新生成一个数组,并存入值,否则则将值存入数组中
判断规则为 原来值的长度的1.5倍比传入的值大则创建一个新的数组,数组长度为原来的1.5倍,如果小的话 就创建一个长度为传入参数的数组,最后还有个判断是判断数组最大长度,如果新生成的那个数组长度值比系统定义的数组最大长度还大,那么将创建一个数组,此数组长度为系统默认的最大长度
/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; 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 */ 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 void ensureCapacityInternal(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(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; }
ArrayList add(int index, E element) 指定插入位置
先验证要插入的位置是否在数组中,然后用跟上面原理一样的方式创建一个新数组,并且新数组,然后调用系统最底层方法System.arraycopy复制一个数组出来,将当前值存入复制出来的集合中的index位置,因为这里多了一个元素,所以要将AarrayList中的size+1
/** * Inserts the specified element at the specified position in this * list. Shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
remove(int index)方法 删除指定下标的元素
Object 返回值 先验证下标是否可用,然后得到当前对象,得到System.arraycopy要复制长度的值,因为下面是要从传入数组的下一个值开始复制,因此这里要减1否则取值时要越界,因为原有的值从新数组中删除,所以原有的值后面所有值都会前进一位,导致数组最后一位无值,因此需要将最后一位赋值为空
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }
remove(Object o)方法 根据对象删除集合中元素
boolean 返回值 判断传入的对象是否在数组中,存在则执行remove(int index)的原理,并返回true,否则返回false
/** * Removes the first occurrence of the specified element from this list, * if it is present. If the list does not contain the element, it is * unchanged. More formally, removes the element with the lowest index * <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> * (if such an element exists). Returns <tt>true</tt> if this list * contained the specified element (or equivalently, if this list * changed as a result of the call). * * @param o element to be removed from this list, if present * @return <tt>true</tt> if this list contained the specified element */ public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }
/* * Private remove method that skips bounds checking and does not * return the value removed. */ private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work }
clear()方法
此方法为情况当前集合,也就是清空数组,但需要注意的是,该方法不会改变数组的长度,只会将数组的值赋为空
/** * Removes all of the elements from this list. The list will * be empty after this call returns. */ public void clear() { modCount++; // Let gc do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
注意事项
集合当中只能放置对象的引用,无法放置原生数据类型,我们需要使用原生数据类型的包装类才能加入到集合当中;
集合当中放置的都是Object类型,因此取出来的也是Object类型,那么我们必须要使用强制类型转换将其转换为真正的类型(放置进去的类型);
总结
通过阅读ArrayList的源码才知道,原来ArrayList的底层是用数组实现的,并且add方法是用创建数组的方式来增长边界的。
相关文章推荐
- java ArrayList 源码 解析
- Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例
- JAVA源码学习-ArrayList
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- Java集合源码学习笔记(五)ArrayList,LinkedList,Vector和Hashtable,HashMap的比较
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- java之ArrayList源码解析
- Java中ArrayList源码解析
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- Java集合源码学习(2):ArrayList和LinkedArrayList(未完待续...)
- java ArrayList源码学习
- List接口实现类-ArrayList、Vector、LinkedList集合深入学习以及源码解析
- Java集合源码学习(6)_List接口的实现_ArrayList_Vector
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- [Java]JDK源码学习(1)ArrayList和Vector
- java ArrayList 源码解析(jdk1.6)
- Java 源码解析之 ArrayList
- 【转】Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
- JDK源码学习(3)-java.util.ArrayList与LinkedList
- Java集合源码学习笔记(二)ArrayList分析