ArrayList
ArrayList 实现于 List,RanomAccess
接口。可以插入空数据,也支持随机访问
ArrayList相当于动态数据,其中最重要的两个属性分别是:elementData数组,以及size大小,在调用add()方法的时候:
public boolean add(E e){
ensureCapactiyInternal(size +1);
elementData[size++] =e;
retrun true;
}
1,首先进行扩容校验
2,将插入的值放到尾部,并将size+1.
如果调用add (index ,e)在指定位置添加的话:
pubilc void add(int index ,E element){
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1);
//复制,向后移动
System.arraycopy(elementData, index, elementData,index +1,size-index)
elementData[index] =element;
size++;
}
1,也是首先扩容校验
2,接着对数据进行复制,目的是把index位置空出来放本次插入的数据,并将后面的数据
向后移动一个位置
其实扩容最终调用的代码:
private void grow(int minCapacity){
int oldCapactiy =elementData.length;
int newCapacity=oldCapactiy +(oldCapactiy >> 1);
if(newCapcity -minCapacity <0)
newCapcity=minCapacity ;
if(newCapcity-MAX_ARRAY_SIZE >0)
newCapcity=hugeCapacity(minCapacity);
elementData =Arrays.copyOf(elementData ,newCapacity);
}
也是一个数组复制的过程
由此可见ArrayList的主要消耗是数组扩容以及在指定位置添加数据,在日常使用时最好是指定大小,尽量减少扩容,
更要减少在指定位置插入数据的操作
序列化
由于ArrayList是基于动态数组实现的,所以并不是所有的空间都被使用,因此transient修饰,可以防止被自动序列化
transient Object[] elementData;
因此ArrayList自定义了序列化和反序列化:
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
int expectedModCount =modCount;
s.defalutWriteObject();
s.writeInt(size);
//只序列化了被使用的数据
for(int i =0; i<size ; i++){
s.writeObject(elementData[i]);
}
if(modCount != exceptedModCount){
throw new ConcurrentModifacationException();
}
}
private void readObject(java.io.ObjectInputStream s)
throw java.io.IOException ,ClassNotFoundException{
elementData =EMPTY_ELEMENTDATA;
s.defaultReadObject();
s.readInt();
if(size >0){
ensureCapacityInternal(size);
Object[] a=elementData;
for(int i=0; i<size; i++){
a[i]=s.readObject();
}
}
}
当对象中自定义了writeObject和readObject方法时,JVM会调用这两个自定义方法来实现序列化和反序列化
所以从实现中可以看出ArrayList只序列化了被使用的数据
来源:oschina
链接:https://my.oschina.net/u/4196595/blog/3178405