一、ArrayList
内部是由一个Object[] 数组实现
private
transient
Object[]
elementData
;
private
int
size
;
1、ArrayList里面元素的个数,这里要注意一下,size是按照调用add、remove方法的次数进行自增或者自减的,所以add了一个null进入ArrayList,size也会加1
2、ArrayList不是线程安全的,所以在多线程的环境下使用ArrayList需要注意ArrayList类型变量的线程同步问题。当然,有一种方式可以创建一个线程安全的ArrayList:
List list = Collections.synchronizedList(new ArrayList(…));
3、ArrayList 所有操作都是围绕数组进行的,Arrays.copyOf 方法
4、为什么ArrayList的elementData是用transient修饰的?
public
class
ArrayList<E>
extends
AbstractList<E>
implements
List<E>
, RandomAccess, Cloneable, java.io.Serializable
看到ArrayList实现了Serializable接口,这意味着ArrayList是可以被序列化的,用transient修饰elementData意味着我不希望elementData数组被序列化。这是为什么?因为序列化ArrayList的时候,ArrayList里面的elementData未必是满的,比方说elementData有10的大小,但是我只用了其中的3个,那么是否有必要序列化整个elementData呢?显然没有这个必要,因此ArrayList中重写了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 array length
s.writeInt(elementData.length);
//
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();
}
}
每次序列化的时候调用这个方法,先调用defaultWriteObject()方法序列化ArrayList中的非transient元素,elementData不去序列化它,然后遍历elementData,只序列化那些有的元素,这样:
1、加快了序列化的速度
2、减小了序列化之后的文件大小
不失为一种聪明的做法,如果以后开发过程中有遇到这种情况,也是值得学习、借鉴的一种思路。
添加、删除元素:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
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
;
}
//添加元素核心代码
private
void
ensureCapacityInternal
(
int
minCapacity
) {
if
(
elementData
==
EMPTY_ELEMENTDATA
) {
minCapacity
= Math.
max
(
DEFAULT_CAPACITY
,
minCapacity
);
}
ensureExplicitCapacity(
minCapacity
);
}
private
void
ensureExplicitCapacity(
int
minCapacity
) {
modCount
++;
// overflow-conscious code
if
(
minCapacity
-
elementData
.
length
> 0)
grow(
minCapacity
);
}
/**
* 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;
/**
* 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
static
int
hugeCapacity(
int
minCapacity
) {
if
(
minCapacity
< 0)
// overflow
throw
new
OutOfMemoryError();
return
(
minCapacity
>
MAX_ARRAY_SIZE
) ?
Integer.
MAX_VALUE
:
MAX_ARRAY_SIZE
;
}
ArrayList的优点如下:
1、ArrayList底层以数组实现,是一种
随机访问
模式,再加上它实现了RandomAccess接口,因此查找也就是get的时候非常快
2、ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已
不过ArrayList的缺点也十分明显:
1、删除元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能
2、插入元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能
因此,
ArrayList比较适合顺序添加、随机访问的场景
。