transient
java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
ArrayList主要的几个成员变量
private static final int DEFAULT_CAPACITY = 10; //默认的数组的大小
private static final Object[] EMPTY_ELEMENTDATA = {};//默认的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认的数组,没什么不同,只是在不同的构造函数调用
主要的构造函数
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
-
在这个构造函数里面只是初始化了一个空的数据elementData
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); }}
-
这个构造函数初始化一个我们指定大小的Object数组.
查看add方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
//将添加的元素设置到数组的末尾
elementData[size++] = e;
return true;
}
- add方法里面第一件事是来设置数组大小
- 第二来给数组设置值
ensureCapacityInternal
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //这个判断主要是给集合添加第一个元素的时候,来指定默认的数组大小
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//主要的扩展数组大小的方法
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //这个属性主要是用来记录集合变化的次数
// overflow-conscious code
//判断最小容量与数组的长度,当最小容量大于数组的长度的时候,说明数组的内存太小需要扩展
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
grow扩展最小的容量
private void grow(int minCapacity) {
// overflow-conscious code
//当第一次往集合添加元素时候
//elementData数组是一个空的数组,oldCapacity=0;
int oldCapacity = elementData.length;
//新的数组空间 newCapacity=oldCapacity+(oldCapacity >> 1)=0+0=0;第一次添加的时候,新的数组空间的大小也是0
int newCapacity = oldCapacity + (oldCapacity >> 1);
//第一次0-10=-10成立
if (newCapacity - minCapacity < 0)
//将新的数组空间设置成minCapacity=10;
newCapacity = minCapacity;
//判断数组最大时,数组空间的大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//重新创建一个长度为newCapacity的数组,将elementData数据复制到新的数组中,并且将这个新的数组赋值给elementData
elementData = Arrays.copyOf(elementData, newCapacity);
}
> 在网上看到oldCapacity >> 1就是oldCapacity/2 oldCapacity << 1 就是 oldCapacity*2 ,还需要学习一下位运算原理
remove方法
public E remove(int index) {
//判断移除的index大于,等于数组长度时候,就会报IndexOutOfBoundsException
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//用来统计数据变化的次数,可以不用管它
modCount++;
//获取到要移除的的元素
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
//判断移除的元素是不是最后一个元素,要是不是最后一个元素就不需要在copy一个新的数组出来
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//返回删除的元素
elementData[--size] = null; // clear to let GC do its work
//返回删除的元素
return oldValue;
}
System提供了一个静态方法arraycopy(),我们可以使用它来实现数组之间的复制。其函数原型是:
public static void (Object src,
int srcPos,
Object dest,
int destPos,
int length)
src:源数组; srcPos:源数组要复制的起始位置; dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度。 注意:src and dest都必须是同类型或者可以进行转换类型的数组.
set方法
public E set(int index, E element) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//获取index上的旧的元素
E oldValue = (E) elementData[index];
//设置新的元素
elementData[index] = element;
return oldValue;
}
获取一个值lastIndex
public int lastIndexOf(Object o) {
if (o == null) {//判断o
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
//将数组从末尾开始循环遍历,找到相等的值,返回值的下标index
if (o.equals(elementData[i]))
return i;
}
return -1;
}
重载的add方法add(int index, E element)
public void add(int index, E element) {
if (index > size || index < 0) //这里判断位置是否IndexOutOfBoundsException
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//这里也是设置数组的大小
ensureCapacityInternal(size + 1); // Increments modCount!!
//主要是这里,复制一个新的数组
//假如以前的数组是 [1,2,3]这个样子,我们需要再Index=2的位置添加一个元素4
//那么使用arraycopy复制后的数组会变成[1,2,,3]
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//设置数组指定位置指定的element,新的数组就会变成[1,2,4,3]
elementData[index] = element;
//设置数组的长度增加1
size++;
}
- 顺序存储线性表