ArrayList
ArrayList是list adt的一种可增长数组的实现
时间复杂度:
printList:O(N)
findKth: O(1)
删除和插入平均花费线性时间 O(N)
源码分析
1.构造方法
构造方法有三个
public ArrayList()
public ArrayList(int initialCapacity);
public ArrayList(Collection<? extends E> c);
第一个是无参,elementData是保存数据的数组。这里将其赋值为一个默认的空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
第二个使用给定的容量来初始化。当参数大于0时,直接初始化给定容量的数组。
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);
}
}
第三个是用给定的集合初始化,直接将c转成数组赋值给elemenetData。c.toArray()的类型可能不是Object[].class,List strs= Arrays.asList(“hehe”),strs的类型为 [Ljava.lang.String; 所以要用copyof方法转换,这个方法返回的是Object[].class型的,所以就有可能产生当前的list类型错误,如下图所示:
public ArrayList(Collection<? extends E> c)
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
2. 添加元素
先确保容量,然后set值。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
3.扩容: 构造方法中是一个空数组,添加第一个元素时,扩容为10,之后扩容为原容量的1.5倍
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);
}
4. remove,用arraycopy实现。
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; // clear to let GC do its work
return oldValue;
}
5.addAll方法没有类型检查,所以List类型的arrayList可以添加实际类型为String的 list
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
6.序列化,为什么要讲序列化,大家有没有注意到elementData是用transient修饰的,用transient关键字标记的成员变量不参与序列化过程。
transient Object[] elementData;
List<String> ints=new ArrayList<>();
for(int i=0;i<5;i++){
ints.add(i+"");
}
FileOutputStream fos=new FileOutputStream(".\\src\\main\\java\\me\\ffulauh\\javalang\\collectiondemo\\list\\list");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(ints);
FileInputStream fis=new FileInputStream(".\\src\\main\\java\\me\\ffulauh\\javalang\\collectiondemo\\list\\list");
ObjectInputStream ois=new ObjectInputStream(fis);
List ints2=(List)ois.readObject();
序列化的时候elementData的长度为10,序列化后,长度为5,证实它没有被序列化。
再来看看源码,writeObject中写入的是实际的元素,而不是整个数组
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}