1、 ArrayList
1.1 简介
ArrayList是一种以动态数组实现的List集合。其中,元素可以为空值或重复,当元素数量大于其底层数组容量时,其会通过扩容机制重新生成一个更大的数组;其次,ArrayList 是非线程安全类。
1.2 继承关系
List 提供了基础的添加、删除、遍历等操作。RandomAccess 提供了随机访问的能力。Cloneable,可以被克隆。Serializable,可以被序列化。
1.3 源码解析
1.3.1 属性
private static final int DEFAULT_CAPACITY
= 10;
private static final Object
[] EMPTY_ELEMENTDATA
= {};
private static final Object
[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA
= {};
transient Object
[] elementData
;
private int size
;
1.3.2 构造函数
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
);
}
}
public ArrayList() {
this.elementData
= DEFAULTCAPACITY_EMPTY_ELEMENTDATA
;
}
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 {
this.elementData
= EMPTY_ELEMENTDATA
;
}
}
补充:数组拷贝
Arrays
.copyOf():
public static <T,U> T
[] copyOf(U
[] original
, int newLength
, Class
<? extends T[]> newType
) {
@SuppressWarnings("unchecked")
T
[] copy
= ((Object
)newType
== (Object
)Object
[].class)
? (T
[]) new Object[newLength
]
: (T
[]) Array
.newInstance(newType
.getComponentType(), newLength
);
System
.arraycopy(original
, 0, copy
, 0,
Math
.min(original
.length
, newLength
));
return copy
;
}
System
.arraycopy():
public static native void arraycopy(Object src
, int srcPos
,
Object dest
, int destPos
,
int length
);
1.3.3 添加元素
add(E e)方法: 尾部插入
public boolean add(E e
) {
ensureCapacityInternal(size
+ 1);
elementData
[size
++] = e
;
return true;
}
private void ensureCapacityInternal(int minCapacity
) {
ensureExplicitCapacity(calculateCapacity(elementData
, minCapacity
));
}
private static int calculateCapacity(Object
[] elementData
, int minCapacity
) {
if (elementData
== DEFAULTCAPACITY_EMPTY_ELEMENTDATA
) {
return Math
.max(DEFAULT_CAPACITY
, minCapacity
);
}
return minCapacity
;
}
private void ensureExplicitCapacity(int minCapacity
) {
modCount
++;
if (minCapacity
- elementData
.length
> 0)
grow(minCapacity
);
}
private void grow(int minCapacity
) {
int oldCapacity
= elementData
.length
;
int newCapacity
= oldCapacity
+ (oldCapacity
>> 1);
if (newCapacity
- minCapacity
< 0)
newCapacity
= minCapacity
;
if (newCapacity
- MAX_ARRAY_SIZE
> 0)
newCapacity
= hugeCapacity(minCapacity
);
elementData
= Arrays
.copyOf(elementData
, newCapacity
);
}
add(int index, E element):其他位置插入
public 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.3.4 获取元素
public E
get(int index
) {
rangeCheck(index
);
return elementData(index
);
}
1.3.5 删除元素
remove(Object o)方法
public boolean remove(Object o
) {
if (o
== null
) {
for (int index
= 0; index
< size
; index
++)
if (elementData
[index
] == null
) {
fastRemove(index
);
return true;
}
} else {
for (int index
= 0; index
< size
; index
++)
if (o
.equals(elementData
[index
])) {
fastRemove(index
);
return true;
}
}
return false;
}
private void fastRemove(int index
) {
modCount
++;
int numMoved
= size
- index
- 1;
if (numMoved
> 0)
System
.arraycopy(elementData
, index
+1, elementData
, index
,
numMoved
);
elementData
[--size
] = null
;
}
remove(int index)方法
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
;
return oldValue
;
}
1.3.6 手动缩容
public void trimToSize() {
modCount
++;
if (size
< elementData
.length
) {
elementData
= (size
== 0)
? EMPTY_ELEMENTDATA
: Arrays
.copyOf(elementData
, size
);
}
}
1.4 总结
ArrayList 具有随机访问的能力,如果在一些效率要求比较高的场景下: for (int i = 0; i < list.size(); i++) foreach 最终会被转换成迭代器遍历的形式,效率不如上面的遍历方式
ArrayList 迭代器中的方法都是均具有快速失败的特性,当遇到并发修改的情况时,迭代器会快速失败,以避免程序在将来不确定的时间里出现不确定的行为
remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。
elementData定义为transient的优势,自己根据size序列化真实的元素,而不是根据数组的长度序列化元素,减少了空间占用。