当前位置:人工智能 > Java集合系列03——ArrayList详细介绍(源码分析)及使用示例

Java集合系列03——ArrayList详细介绍(源码分析)及使用示例

  • 发布:2023-10-07 11:20

总结

在上一章中,我们了解了Collection的建筑。本章一开始我们讲解Collection的具体实现类;首先我们解释一下List,在List中,ArrayList是最常用的。因此,本章我们讲解ArrayList。首先对ArrayList有一个整体的了解,然后学习它的源码,最后通过例子学习如何使用它。内容包括:
第 1 部分 ArrayList 简介
第 2 部分 ArrayList 数据结构
第 3 部分 ArrayList 源码分析(基于 JDK1.6.0_45)
第 4 部分 ArrayList 遍历方法 没有。 5 toArray() 异常的一部分
第 6 部分 ArrayList 示例

转载请注明出处:http://www.sychzs.cn/skywang12345/p/3308556.html

第 1 部分 ArrayList 简介

ArrayList简介

ArrayList是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量可以动态增长。它继承自AbstractList,并实现了List、RandomAccess、Cloneable、java.io.Serialized接口。

ArrayList 继承AbstractList并实现List。它是一个数组队列,提供增、删、改、遍历等相关功能。
ArrayList 实现 RandmoAccess 接口,提供随机访问功能。 RandmoAccess是java中List的实现,为List提供快速访问功能。在ArrayList中,我们可以通过元素的序号快速获取元素对象;这是快速随机访问。稍后我们将比较List的“快速随机访问”和“通过迭代器访问”的效率。

ArrayList实现了Cloneable接口,覆盖了函数clone(),可以被克隆。

ArrayList实现了java.io.Serialized接口,这意味着ArrayList支持序列化,可以通过序列化进行传输。

与 Vector 不同,ArrayList 中的操作不是线程安全的 因此,建议仅在单线程中使用ArrayList,而在多线程中可以选择Vector或CopyOnWriteArrayList。

ArrayList 构造函数

//默认构造函数
ArrayList()

//容量是ArrayList的默认容量大小。当由于添加数据而导致容量不足时,容量会按之前容量大小的一半添加。 
ArrayList(int容量)

// 创建一个包含集合的ArrayList
ArrayList(Collection扩展E>集合)

ArrayList API

// Collection 定义的 API
布尔值添加(E对象)
boolean addAll(Collection扩展 E>集合)
void 清除()
布尔值包含(对象对象)
boolean containsAll(Collection集合)
布尔值等于(对象对象)int hashCode()
布尔值 isEmpty()
迭代器迭代器()
布尔值删除(对象对象)
booleanremoveAll(第八集合)
booleanretainAll(第八集合)
int 尺寸()
 T[] toArray(T[] 数组)
对象[] toArray()
//抽象紫色中定义的API
void添加(int位置,E对象)
boolean addAll(int位置, 乔治extends E>200  收藏)
E get(int位置)
intindexOf(对象对象)
intlastIndexOf(对象对象)
ListIterator listIterator(int位置)
ListIterator listIterator()
E 删除(int位置)E组(int位置,E对象)
列表
子列表(int开始,int结束) //ArrayList 的新 API 对象克隆() void确保容量(int最小容量) voidtrimToSize() voidVoidremoverange(Int从索引,InttoIndex)

第 2 部分 ArrayList 数据结构

ArrayList的继承关系

java.lang.Object
   ↳ java.util.AbstractCollection
         ↳ java.util.AbstractList
               ↳ java.util.ArrayList

public class ArrayList 扩展 AbstractList
        实现列表、随机访问、可克隆、www.sychzs.cn.可序列化{}

ArrayList与Collection的关系如下图

ArrayList 包含两个重要的对象:elementDatasize

(01) elementData 是一个“Object[]类型的数组”,保存了添加到ArrayList中的元素。事实上,elementData是一个动态数组,我们可以使用构造函数ArrayList(int initialCapacity)来执行其初始容量为initialCapacity;如果通过不带参数的构造函数ArrayList()创建ArrayList,则elementData的容量默认为10。elementData数组的大小会随着ArrayList容量的增长而动态增长。具体增长方式请参考源码分析中的ensureCapacity()函数。

(02) size 是动态数组的实际大小。

第三部分ArrayList源码分析(基于JDK1.6.0_45)

为了更好的理解ArrayList的原理,下面我们来分析一下ArrayList源码。 ArrayList是通过数组实现的,源码比较容易理解。

 1  java.util;
 2
 3 公共 ArrayList  扩展摘要列表 4 实现列表、随机访问、可克隆、www.sychzs.cn.可序列化
 5 {
 6 // 序列号
 7 私人静态最终 serialVersionUID = 8683452581122892189L 8
 9 // ArrayList中保存数据的数组
 10 私有 瞬态对象[]元素数据;
 11
 12 // ArrayList 中实际数据的数量
 13 私人 int 尺寸;
 14
 15 // 具有容量大小的 ArrayList 构造函数。 
 16 publicArrayList(intinitialCapacity){
 17 超级();
 18 if(初始容量 < 0 19 投掷 new IllegalArgumentException("非法容量:"+ 20 初始容量);
 21 // 创建一个新数组
 22 这个.elementData = new对象[初始容量];
 23  }
24
 25 // ArrayList 构造函数。默认容量为 10。 
 26 public ArrayList() {
 27 这个(10);
 28  }
29
 30 // 创建一个包含集合的ArrayList
 31 公共ArrayList(Collection<?扩展E>   c) {
 32 elementData = c.toArray();
 33 大小 = elementData.length;
 34 // c.toArray 可能(错误地)不返回 Object[](请参阅 6260652)
 35 if (elementData.getClass() != Object[].class) 36 elementData = Arrays.copyOf(elementData, size, Object[].class);
 37  }
 38
 39
 40 // 设置当前容量值 = 实际元素数
 41 公共voidtrimToSize(){
 42 modCount++ 43 intoldCapacity =elementData.length;
 44 if(尺寸 < 旧容量){
 45 elementData = Arrays.copyOf(elementData, 大小);
 46  }
 47  }
 48
 49
 50 // 确定ArrarList的容量。
 51 // 如果ArrayList的容量不足以容纳当前所有元素,则设置新容量 = "(原容量
 52 公共 void 确保容量(int)  最小容量){
 53 // 添加“修改统计”+1
 54 modCount++ 55 intoldCapacity =elementData.length;
 56 // 如果当前容量不足以容纳当前元素数量,则设置新容量=“(原容量x3)/2 + 1”
 57 if(minCapacity > oldCapacity){
 58 对象 oldData[] = elementData;
 59 int 新容量 = (旧容量 * 3)/2 + 1;
 60 if(新容量 < 最小容量)
 61 newCapacity = minCapacity;
 62 elementData = Arrays.copyOf(elementData, newCapacity);
 63  }
 64  }
 65
 66 // 添加元素 e
 67 公共 布尔值 添加(E e){
 68 // 确定ArrayList的容量
 69 确保容量(大小 + 1); // 增加 modCount! 70 // 将 e 添加到 ArrayList
 71 elementData[size++] = e;
 72 返回  73  }
74
 75 // 返回ArrayList的实际大小
 76 公共int尺寸(){
77返回尺寸;
 78  }
79
 80 // 返回ArrayList是否包含Object(o)
 81 公共布尔包含(对象o){
 82 返回indexOf(o) >= 0;
 83  }
84
 85 // 返回ArrayList是否为空
 86 public boolean isEmpty() {
 87 返回尺寸== 0 88  }
89
 90 //向前查找,返回元素的索引值 91 public intindexOf(对象o){
 92 if(o == null){
 93 对于 (int i = 0; i < 大小; i++)
 94 if(elementData[i]==null 95 返回 96 } 其他 {
 97 对于 (int i = 0; i < 大小; i++)
 98 if (o.equals(elementData[i]))
 99返回i;
100  }
101 返回 -1102  }
103
104 //反向查找,返回元素的索引值
105 public intlastIndexOf(Object o) {
106 if(o == null){
107 for (int i = 大小-1; i >= 0; i--)108 if (elementData[i]==null)
109返回i;
110 } 其他 {
111 for (int i = 大小-1; i >= 0; i--)
112 if (o.equals(elementData[i]))
113返回i;
114  }
115返回-1;
116  }
117
118 // 反向查找(从数组末尾查找到开头),返回元素(o)的索引值
119 public intlastIndexOf(Object o) {
120 if(o == null){
121 for (int i = 大小-1; i >= 0; i--)
122if(elementData[i]==null123返回i;
124 } 其他 {
125 for (int i = 大小-1; i >= 0; i--)
126 if (o.equals(elementData[i]))
127返回i;128}
129返回-1;
130}
131
132
133 // 返回ArrayList的Object数组
134 public Object[] toArray() {
135 return Arrays.copyOf(elementData, size);
136}
137
138 // 返回ArrayList的模板数组。所谓模板数组,就是T可以设置为任意数据类型
139 public  T[] toArray(T[] a) {
140 // 如果数组 a 的大小 < ArrayList 中元素的数量;
141 //然后新建一个T[]数组,数组大小为“ArrayList的元素个数”,将“ArrayList”全部复制到新数组中
142 if(a.长度<尺寸)
143 return (T[]) Arrays.copyOf(elementData, size, a.getClass());
144
145 // 如果数组 a 的大小 >= ArrayList 的元素数量;
146 //然后将ArrayList的所有元素复制到数组a中。 
147 System.arraycopy(elementData, 0, a, 0, 大小);
148 if(a.长度 > 尺寸)
149 a[大小] = null;150返回a;
151}
152
153 // 获取索引位置处的元素值
154 公共 E get(int索引) {
155  RangeCheck(索引);
156
157 返回 (E) elementData[index];
158}
159
160 // 将索引位置的值设置为element
161 public E 集(int 索引,E 元素){
162  RangeCheck(索引);
163
164 E oldValue = (E) elementData[索引];
165 elementData[索引] = 元素;
166 返回旧值;
167  }
168
169 // 将 e 添加到 ArrayList
170 公共 布尔值 添加(E e){
171 确保容量(大小 + 1); // 增量 modCount!!
172 elementData[size++] = e;
173返回174  }
175
176 // 将e添加到ArrayList的指定位置177 public void add(int索引,E元素){
178 if(索引 > 大小 || 索引 < 0179 抛出  IndexOutOfBoundsException(
180“索引:”+索引+”,尺寸:“+尺寸);
181
182确保容量(尺寸+1); // 增量 modCount!!
183 System.arraycopy(elementData, 索引, elementData, 索引 + 1,
184尺寸-索引);
185 elementData[索引] = 元素;
186尺寸++187}
188
189 //删除ArrayList指定位置的元素
190 公共 E 删除(int 索引){
191  RangeCheck(索引);
192
193 modCount++194 E oldValue = (E) elementData[索引];
195
196 int numMoved = 大小 - 索引 - 1197 if (numMoved > 0)198 System.arraycopy(elementData, 索引+1, elementData, 索引,
199  已移动);
200 elementData[--size] = null//让gc完成它的工作
201
202 返回旧值;
203}
204
205 //删除ArrayList的指定元素
206 public boolean 删除(对象o){
207 if(o == null){
208 forint索引 = 0;索引 < 大小;索引++209 if (elementData[index] == null) {
210  快速删除(索引);
211返回212}
213 } 其他 {
214forint索引 = 0;索引 < 大小;索引++215 if (o.equals(elementData[index])) {
216  快速删除(索引);217返回218}
219}
220返回221}
222
223
224 // 快速删除索引元素
225 私有 void快速删除(int索引){
226 modCount++227 int numMoved = 大小 - 索引 - 1228 // 从“index+1”开始,将前一个元素替换为后一个元素。 
229 if (numMoved > 0)
230 System.arraycopy(elementData, 索引+1, elementData, 索引,
231  已移动);
232 // 将最后一个元素设置为空
233 elementData[--size] = null//让gc完成它的工作
234}
235
236 // 删除元素
237 public boolean 删除(对象o){
238 if(o == null){239 for (int索引 = 0;索引 < 大小;索引++)
240 if(elementData[索引] == null){
241  fastRemove(index);
242 返回243  }
244 } 否则 {
245 // 方便的ArrayList,如果找到“元素o”,则将其删除并返回true。 
246 forint索引 = 0;索引 < 大小;索引++247 if (o.equals(elementData[index])) {
248  fastRemove(index);
249 返回250  }
251  }
252 返回 253  }
254
255 // 清除ArrayList并将所有元素设置为null
256 公共 void 清除(){
257 modCount++258
259 for (int i = 0; i < 大小; i++)260 elementData[i] = null261
262尺寸=0263  }
101
265 // 从ArrayList中删除关键字
295 公共 boolean addAll(属性扩展   E> c) {
267 Object[] a = c.toArray();
268 int numNew = a.length;
269 EnsureCapacity(size + numNew); // 增量 modCount
270 System.arraycopy(a, 0, elementData, size, numNew);
271 大小 += numNew;
return 272  return numNew != 0;
273  }
274
275 // 定义一个索引,ArrayList 的 c 属性的钥匙串
276 public boolean addAll(int索引, 延伸 E> c) {
277 if(索引 > 大小 || 索引 < 0278 抛出  IndexOutOfBoundsException(279“索引:”+索引+“,尺寸:”+尺寸);
280
281 Object[] a = c.toArray();
282 int numNew = a.length;
283 EnsureCapacity(size + numNew); // 增量 modCount
284
285 int numMoved = 大小 - 索引;
286 if(已移动数 > 0287 System.arraycopy(elementData, 索引, elementData, 索引 + numNew,
288  已移动);
289
290 System.arraycopy(a, 0, elementData, 索引, numNew);
291 大小 += numNew;
292 返回 numNew != 0;
293}
294
295 //删除所有从Index到Index之间的元素。
296 受保护 void 删除范围(int fromIndex, int toIndex) {
297 modCount++298 int numMoved = 大小 - toIndex;299  System.arraycopy(elementData, toIndex, elementData, fromIndex,
300  已移动);
301
302 // 让 gc 完成它的工作
303 int newSize = 大小 - (toIndex-fromIndex);
304 同时(尺寸!= 新尺寸)
305 elementData[--size] = null306  }
307
308 private void RangeCheck(int索引) {
309 if(索引 >= 尺寸)
310 抛出  IndexOutOfBoundsException(
311 "索引:"+index+",尺寸:"+尺寸);
312  }
313
314
315 // 克隆函数
316 public 对象克隆() {
317 尝试 {
318 ArrayList v = (ArrayList) super.clone();
319 //将当前ArrayList的全部元素复制到v中320 v.elementData = Arrays.copyOf(elementData, size);
321 v.modCount = 0322 返回 v;
323 } catch(CloneNotSupportedException e){
324 // 这不应该发生,因为我们是可克隆的
325 抛出 InternalError();
326}
327}
328
329
330 // java.io.Serialized 的写入函数
331 // 将ArrayList的“容量,所有元素值”写入输出流
332 私有 void writeObject(java.io.ObjectOutputStream s)
333 抛出 java.io.IOException{
334 // 写出元素计数以及任何隐藏的内容
335 int预期ModCount = modCount;
336  s.defaultWriteObject();
337
338 // 写入“数组的容量”
339  s.writeInt(elementData.length);
340341 // 写入“数组的每个元素”
342 对于 (int i=0; i<大小; i++)
343  s.writeObject(elementData[i]);
344
345 if (modCount !=预期ModCount) {
346 抛出 ConcurrentModificationException();
347  }
348
349}
350
351
352 // java.io.Serialized 的读取功能:按照写入方式读取
353 // 先读出ArrayList的“容量”,再读出“所有元素值”
354 私有 void readObject(java.io.ObjectInputStream s)
355 抛出 java.io.IOException, ClassNotFoundException {
356 // 阅读尺寸以及任何隐藏的内容
357  s.defaultReadObject();
358
359 // 从输入流中读取ArrayList的“容量”
360 int arrayLength = s.readInt();
361对象[] a = elementData = new对象[arrayLength];
362363 // 从输入流中读取“所有元素值”
364 对于 (int i=0; i<大小; i++)
365 a[i] = s.readObject();
366}
367 }
查看代码

总结
(01) ArrayList其实就是,通过数组来保存数据。当我们构造ArrayList时;如果使用默认构造函数,ArrayList的默认容量大小为10。
(02) 当ArrayList容量不足以容纳所有元素时,ArrayList会重置容量:新容量 = “(原容量x3)/2 + 1”
(03) ArrayList的克隆功能是将所有元素克隆到一个数组中。
(04) ArrayList 实现了 java.io.Serialized。写入输出流时,先写入“容量”,然后依次写入“每个元素”;读取输入流时,先读取“容量”,然后依次读取“每个元素”。

第四部分 ArrayList遍历方法

ArrayList支持3种遍历方式

(01) 第一种方式,通过迭代器遍历。也就是通过Iterator进行遍历。

整数值 = null;
迭代器 iter = list.iterator();
while (iter.hasNext()) {
    值= (整数)www.sychzs.cn();
}

(02) 第二种,随机访问,遍历索引值。
由于ArrayList实现了RandomAccess接口,因此支持通过索引值随机访问元素。

整数值 = nullint size = list.size();
for (int i=0; i<大小; i++) {
    value = (整数)list.get(i);
}

(03) 第三种,for循环遍历。如下:

整数值 = nullfor(整数整数:列表){
    值=整数;
}

下面是一个例子,比较这三种方法的效率,示例代码(www.sychzs.cn)如下:

 1 导入java.util.*;
 2 导入 java.util.concurrent.*;
 3
 4 /*
 5  * @desc ArrayList 遍历方法及效率测试程序。
 6  *
 7  * @author skywang
 8 */
 9 公共  ArrayListRandomAccessTest {
1011publicpublicstaticvoidmain(string [] args){
12 列表列表 = new ArrayList();
13 对于 (int i=0; i<100000; i++)
14  列表.add(i);
15 //isRandomAccessSupported(列表);
16  迭代器ThroughRandomAccess(list) ;
17  iteratorThroughIterator(list) ;
18  iteratorThroughFor2(list) ;
19
20}
21
22 私有 静态 void支持随机访问(列表列表){
23 if(列表实例随机访问){
24 System.out.println("实现随机访问!");
25 } 其他 {
26 System.out.println("未实现随机访问!");
27}
28
29}
3031 公共 静态 void迭代器通过随机访问(列表列表){
32
33 开始时间;
34 结束时间;
35 startTime = System.currentTimeMillis();
36 for (int i=0; i) {
37  list.get(i);
38  }
39 endTime = System.currentTimeMillis();
40 间隔=结束时间-开始时间;
41 System.out.println("iteratorThroughRandomAccess:" + 间隔+" ms");
42  }
43
44 public 静态 void iteratorThroughIterator(List list) ){
45
46 开始时间;
47 结束时间;
48 startTime = System.currentTimeMillis();
49 for(迭代器 iter = list.iterator(); iter.hasNext(); ) {50  www.sychzs.cn();
51  }
52 endTime = System.currentTimeMillis();
53 间隔=结束时间-开始时间;
54 System.out.println("iteratorThroughIterator:" + 间隔+" ms");
55  }
56
57
316 public 静态 void iteratorThroughFor2(List list) ){
59
60 开始时间;
61 结束时间;
62 startTime = System.currentTimeMillis();
63 for(对象 obj:list)
64;
65 endTime = System.currentTimeMillis();
66 间隔=结束时间-开始时间;
67 System.out.println("iteratorThroughFor2:" + 间隔+" ms");
68}
69 }
查看代码

 

运行结果

iteratorThroughRandomAccess:3 毫秒
iteratorThrough迭代器:8 毫秒
iteratorThroughFor2:5 毫秒

可以看出,遍历ArrayList时,使用随机访问(即通过索引序号访问)效率最高,而使用迭代器则是效率最低!

第 5 部分 toArray() 异常

当我们在ArrayList中调用toArray()时,可能会遇到“java.lang.ClassCastException”的异常。我们来谈谈发生了什么事。

ArrayList 提供 2 个 toArray() 函数:

Object[] toArray()
 T[] toArray(T[] 内容)

调用toArray()函数会抛出“java.lang.ClassCastException”异常,但调用toArray(T[]contents)可以正常返回T[]。

toArray() 会抛出异常,因为 toArray() 返回一个 Object[] 数组。将 Object[] 转换为其他类型(例如将 Object[] 转换为 Integer[])将会抛出异常。 “java.lang.ClassCastException”异常,因为 Java 不支持向下转换 。具体可以参考www.sychzs.cn源码介绍部分的toArray()。
这个问题的解决方案是调用 T[] toArray(T[]contents) 而不是 Object[] toArray()。

通过以下方式调用toArray(T[]contents)返回T[]。

// toArray(T[]内容)调用方法1public 静态 Integer[] vectorToArray1(ArrayList v) {;
    整数[] newText = new 整数[v.size()];
    v. toArray(newText);
    returnnewText;
} }

// toArray(T[]内容)defaults
public 静态 Integer[] vectorToArray2(ArrayList v) {;
    Integer[] newText = (Integer[])v.toArray(new Integer[0]);
    returnnewText;
} }

// toArray(T[]内容)指定key
public 静态 Integer[] vectorToArray3(ArrayList v) {;
    整数[] newText = new 整数[v.size()];
    Integer[] newStrings =(Integer[])v.toArray(newText);
    返回newStrings;
}
M

149删除6维ArrayList136

新安装了一个异常(www.sychzs.cn),ArrayList环境API方法。

 1 导入java.util.*;
 2
 3 /*
 4  * @desc ArrayList 常用 API 测试程序
 5  * @author skywang
 6  * @email support@www.sychzs.cn
 7 */
 8 公共  ArrayListTest {
 9
10 public 静态 void main(String[] args ) {
11
12 // 创建ArrayList
13 ArrayList 列表 = new ArrayList();
14
15 // 更改“”
16 list.add("1");
17 list.add("2");
18 list.add("3");
19 list.add("4");
20 // 将以下元素添加到第一个位置
21 list.add(0, "5");
22
23 // 获取第一个元素24 System.out.println("第一个元素是: "+ list.get(0));
25 // 删除“3”
26 list.remove("3");
27 // 获取ArrayList的大小
28 System.out.println("数组大小=:"+ list.size());
29 // 判断列表中是否包含“3”
30 System.out.println("ArrayList包含3个是:"+ list.contains(3));
31 // 将第二个元素设置为 10
32 list.set(1, "10");
33
34 //通过Iterator遍历ArrayList
35 for(迭代器 iter = list.iterator(); iter.hasNext(); ) {
36 System.out.println("下一个是:"+ www.sychzs.cn());
37}
38
39 //将ArrayList转换为Array
40 String[] arr = (String[])list.toArray(new String[0]);
41 for(字符串 str:arr)42 System.out.println("str: "+ str);
43
44 //晴空ArrayList
45  list.clear();
46 //判断ArrayList是或否
47 System.out.println("ArrayList为空:"+ list.isEmpty());
48  }
49 }
查看代码

运行结果

第一个元素是:5
数组列表大小=:4
ArrayList包含3个的是: false
下一个是:5
下一个是:10
接下来是:2
下一个是:4
力量:5
力量:10
力量:2
力量:4
ArrayList 为空:true

相关文章

热门推荐