ArrayList 个人觉得比较容易理解一点,主要就是一个正常的数组。
public
class
ArrayList<E>
extends
AbstractList<E>
implements
List<E>, RandomAccess, Cloneable, Serializable
{
private
static
final
long
serialVersionUID
= 8683452581122892189L;
private
static
final
int
DEFAULT_CAPACITY
= 10;
private
static
final
Object[]
EMPTY_ELEMENTDATA
=
new
Object[0];
private
static
final
Object[]
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
=
new
Object[0];
transient
Object[]
elementData
;
private
int
size
;
private
static
final
int
MAX_ARRAY_SIZE
= 2147483639;
以上是ArrayList 中定义的属性,默认初始化的大小为10,两个空数组,核心存储数据的数组,记录当前保存数据个数的size ,还有最大的数组大小为2^31-1-8,其中8个大小是保存一些虚拟器的头标签的。
构造函数:
public
ArrayList(
int
paramInt
)
{
if
(
paramInt
> 0) {
this
.
elementData
=
new
Object[
paramInt
];
}
else
if
(
paramInt
== 0) {
this
.
elementData
=
EMPTY_ELEMENTDATA
;
}
else
{
throw
new
IllegalArgumentException(
"Illegal Capacity: "
+
paramInt
);
}
}
参数为数组的开辟大小。
public
ArrayList()
{
this
.
elementData
=
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
;
}
不传参则默认创建一个空数组(在你要存进数组的时候才给你开辟出大小的)
public
ArrayList
(Collection<?
extends
E> paramCollection)
{
this
.elementData = paramCollection.toArray();
if
((
this
.size =
this
.elementData.length) != 0)
{
if
(
this
.elementData.getClass() != [Ljava.lang.Object.
class
) {
this
.elementData = Arrays.copyOf(
this
.elementData,
this
.size, [Ljava.lang.Object.
class
);
}
}
else
{
this
.elementData = EMPTY_ELEMENTDATA;
}
}
直接创建和指定集合一样内容的
添加数据方法:
public
boolean
add
(E
paramE
)
{
ensureCapacityInternal(
this
.
size
+ 1);
this
.
elementData
[(
this
.
size
++)] =
paramE
;
return
true
;
}
不指定位置默认在数组后面添加,效率是最高的时间复杂度为O(1),添加前检查数组大小是否够用,不够用就扩容。
public
void
add(
int
paramInt
, E
paramE
)
{
rangeCheckForAdd(
paramInt
);
ensureCapacityInternal(
this
.
size
+ 1);
System.
arraycopy
(
this
.
elementData
,
paramInt
,
this
.
elementData
,
paramInt
+ 1,
this
.
size
-
paramInt
);
this
.
elementData
[
paramInt
] =
paramE
;
this
.
size
+= 1;
}
想知道这方法干了啥,我觉得有必要弄清楚两个东西:
private
void
rangeCheckForAdd
(
int
paramInt
)
{
if
((
paramInt
>
this
.
size
) || (
paramInt
< 0)) {
throw
new
IndexOutOfBoundsException(outOfBoundsMsg(
paramInt
));
}
}
1.先检查所添加数据的位置合不合理;
public
static
native
void
arraycopy(Object
paramObject1
,
int
paramInt1
, Object
paramObject2
,
int
paramInt2
,
int
paramInt3
);
这是一个本地方法,是将
paramObject1数组对象,从
paramInt1位置开始复制
paramInt3 个
到
paramObject2数组中,从
paramInt2这个位置开始放。
System.
arraycopy
(
this
.
elementData
,
paramInt
,
this
.
elementData
,
paramInt
+ 1,
this
.
size
-
paramInt
);
那么上面这个做的就是将
paramInt开始位置到末尾的数据整体往后移,让
paramInt这位空出来让add的值放进去。
public
boolean
addAll
(Collection<?
extends
E>
paramCollection
)
{
Object[]
arrayOfObject
=
paramCollection
.toArray();
int
i
=
arrayOfObject
.
length
;
ensureCapacityInternal(
this
.
size
+
i
);
System.
arraycopy
(
arrayOfObject
, 0,
this
.
elementData
,
this
.
size
,
i
);
this
.
size
+=
i
;
return
i
!= 0;
}
这方法就比较容易理解了,前面是将单个数据添加到数组中去,现在是将多个数据添加到数组的末尾上去,只不过这多个数据是个集合的形式。
public
boolean
addAll
(
int
paramInt
, Collection<?
extends
E>
paramCollection
)
{
rangeCheckForAdd(
paramInt
);
Object[]
arrayOfObject
=
paramCollection
.toArray();
int
i
=
arrayOfObject
.
length
;
ensureCapacityInternal(
this
.
size
+
i
);
int
j
=
this
.
size
-
paramInt
;
if
(
j
> 0) {
System.
arraycopy
(
this
.
elementData
,
paramInt
,
this
.
elementData
,
paramInt
+
i
,
j
);
}
System.
arraycopy
(
arrayOfObject
, 0,
this
.
elementData
,
paramInt
,
i
);
this
.
size
+=
i
;
return
i
!= 0;
}
这是一个指定位置版的添加多个数据,可以类比指定位置的添加单个数据版的方法,在此不多说。
获取数据方法:
public
E
get
(
int
paramInt
)
{
rangeCheck(
paramInt
);
return
elementData(
paramInt
);
}
比较简单,因为对象是个数组,最快且有效的方法当然是直接用下标了。
另外,每个集合类都会有一个迭代器,用迭代器肯定也是可以获取数据
……
public
Iterator<E> iterator()
{
return
new
Itr(
null
);
}
其中Itr是ArrayList中维护的Iterator 内部类。
我们主要看next()方法就可以知道是怎么获取数据的了。
public
E next()
{
checkForComodification();
int
i
=
this
.
cursor
;
if
(
i
>= ArrayList.
this
.
size
) {
throw
new
NoSuchElementException();
}
Object[]
arrayOfObject
= ArrayList.
this
.
elementData
;
if
(
i
>=
arrayOfObject
.
length
) {
throw
new
ConcurrentModificationException();
}
this
.
cursor
= (
i
+ 1);
return
arrayOfObject
[(
this
.
lastRet
=
i
)];
}
先获取到ArrayLsit中维护的数组,再取下标(跟get中一样)。这个迭代器绕了一圈还是调用了get方法。
删除数据方法:
public
E
remove
(
int
paramInt
)
{
rangeCheck(
paramInt
);
this
.
modCount
+= 1;
Object
localObject
= elementData(
paramInt
);
int
i
=
this
.
size
-
paramInt
- 1;
if
(
i
> 0) {
System.
arraycopy
(
this
.
elementData
,
paramInt
+ 1,
this
.
elementData
,
paramInt
,
i
);
}
this
.
elementData
[(--
this
.
size
)] =
null
;
return
localObject
;
}
这是根据数组下标来删除数据,很简单,将要删除的位置的后面的数据整体往前移一位即可,然后最后一位置空。最后返回你要删除的数据。
public
boolean
remove
(Object
paramObject
)
{
int
i
;
if
(
paramObject
==
null
) {
for
(
i
= 0;
i
<
this
.
size
;
i
++) {
if
(
this
.
elementData
[
i
] ==
null
)
{
fastRemove(
i
);
return
true
;
}
}
}
else
{
for
(
i
= 0;
i
<
this
.
size
;
i
++) {
if
(
paramObject
.equals(
this
.
elementData
[
i
]))
{
fastRemove(
i
);
return
true
;
}
}
}
return
false
;
}
这是根据数据数据来删除,要先遍历数组找到该对象,再进行删除,这fastRemove方法跟前面的remove是一样的,不信你看
private
void
fastRemove
(
int
paramInt
)
{
this
.
modCount
+= 1;
int
i
=
this
.
size
-
paramInt
- 1;
if
(
i
> 0) {
System.
arraycopy
(
this
.
elementData
,
paramInt
+ 1,
this
.
elementData
,
paramInt
,
i
);
}
this
.
elementData
[(--
this
.
size
)] =
null
;
}
确实删除了数据返回true,没有则false。
修改数组数据方法:
public
E
set
(
int
paramInt
, E
paramE
)
{
rangeCheck(
paramInt
);
Object
localObject
= elementData(
paramInt
);
this
.
elementData
[
paramInt
] =
paramE
;
return
localObject
;
}
将指定下标位置中的数据替换即可,最后返回被替换的数据。