ArrayList是最常见以及每个Java开发者最熟悉的集合类了,顾名思义,ArrayList就是一个以数组形式实现的集合,以一张表格来看一下ArrayList里面有哪些基本的元素:
源代码:
/** * 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;
ArrayList类中只定义了两个私有属性,很容易理解,elementData存储ArrayList内的元素,size表示它包含的元素的数量。
有个关键字需要解释:transient。
transient为java关键字,为变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。
对于集合,我认为关注的点主要有四点:
1、是否允许空
2、是否允许重复数据
3、是否有序,有序的意思是读取数据的顺序和存放数据的顺序是否一致
4、是否线程安全
构造函数
ArrayList提供了三个构造函数:
ArrayList():默认构造函数,提供初始容量为10的空列表。
ArrayList(int initialCapacity):构造一个具有指定初始容量的空列表。
ArrayList(Collection extends E> c):构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
/** * 构造一个初始容量为 10 的空列表 */public ArrayList() { this(10);}/** * 构造一个具有指定初始容量的空列表。 */public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); this.elementData = new Object[initialCapacity];}/** * 构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。 */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);}
ArrayList的优缺点
1、ArrayList底层以数组实现,是一种随机访问模式,再加上它实现了RandomAccess接口,因此查找也就是get的时候非常快。
2、ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已。
不过ArrayList的缺点也十分明显:
1、删除元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能。
2、插入元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能。
因此,ArrayList比较适合顺序添加、随机访问的场景。
ArrayList和Vector的区别
ArrayList是线程非安全的,这很明显,因为ArrayList中所有的方法都不是同步的,在并发下一定会出现线程安全问题。那么我们想要使用ArrayList并且让它线程安全怎么办?一个方法是用Collections.synchronizedList方法把你的ArrayList变成一个线程安全的List,比如:
List synchronizedList = Collections.synchronizedList(list);synchronizedList.add("aaa");synchronizedList.add("bbb");for (int i = 0; i < synchronizedList.size(); i++){ System.out.println(synchronizedList.get(i));}
另一个方法就是Vector,它是ArrayList的线程安全版本,其实现90%和ArrayList都完全一样,区别在于:
1、Vector是线程安全的,ArrayList是线程非安全的
2、Vector可以指定增长因子,如果该增长因子指定了,那么扩容的时候会每次新的数组大小会在原数组的大小基础上加上增长因子;如果不指定增长因子,那么就给原数组大小*2,源代码是这样的:
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);
总结
ArrayList基于数组实现,可以通过下标索引直接查找到指定位置的元素,因此查找效率高,但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低。