java集合03--ArrayList源码分析

转载地址:http://blog.csdn.net/wangxiaotongfan/article/details/51329933

概要

上一章,我们学习了Collection的架构。这一章开始,我们对Collection的具体实现类进行讲解;首先,讲解List,而List中ArrayList又最为常用。因此,本章我们讲解ArrayList。先对ArrayList有个整体认识,再学习它的源码,最后再通过例子来学习如何使用它。内容包括:

第1部分 ArrayList简介
第2部分 ArrayList数据结构
第3部分 ArrayList源码解析(基于JDK1.6.0_45)
第4部分 ArrayList遍历方式
第5部分 toArray()异常
第6部分 ArrayList示例

第1部分 ArrayList介绍

ArrayList简介

ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。

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

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

ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

和Vector不同,ArrayList中的操作不是线程安全的所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。

ArrayList构造函数

  
   
    
     [java] 
     view plain
      copy
     
      
     《java集合03--ArrayList源码分析》
     《java集合03--ArrayList源码分析》
    
   
   
 
  1. // 默认构造函数  
  2. ArrayList()  
  3.   
  4. // capacity是ArrayList的默认容量大小。当由于增加数据导致容量不足时,容量会添加上一次容量大小的一半。  
  5. ArrayList(int capacity)  
  6.   
  7. // 创建一个包含collection的ArrayList  
  8. ArrayList(Collection<? extends E> collection)  

ArrayList的API

[java] 
view plain
 copy
 
《java集合03--ArrayList源码分析》
《java集合03--ArrayList源码分析》

  1. // Collection中定义的API  
  2. boolean             add(E object)  
  3. boolean             addAll(Collection<? extends E> collection)  
  4. void                clear()  
  5. boolean             contains(Object object)  
  6. boolean             containsAll(Collection<?> collection)  
  7. boolean             equals(Object object)  
  8. int                 hashCode()  
  9. boolean             isEmpty()  
  10. Iterator<E>         iterator()  
  11. boolean             remove(Object object)  
  12. boolean             removeAll(Collection<?> collection)  
  13. boolean             retainAll(Collection<?> collection)  
  14. int                 size()  
  15. <T> T[]             toArray(T[] array)  
  16. Object[]            toArray()  
  17. // AbstractCollection中定义的API  
  18. void                add(int location, E object)  
  19. boolean             addAll(int location, Collection<? extends E> collection)  
  20. E                   get(int location)  
  21. int                 indexOf(Object object)  
  22. int                 lastIndexOf(Object object)  
  23. ListIterator<E>     listIterator(int location)  
  24. ListIterator<E>     listIterator()  
  25. E                   remove(int location)  
  26. E                   set(int location, E object)  
  27. List<E>             subList(int start, int end)  
  28. // ArrayList新增的API  
  29. Object               clone()  
  30. void                 ensureCapacity(int minimumCapacity)  
  31. void                 trimToSize()  
  32. void                 removeRange(int fromIndex, int toIndex)  

第2部分 ArrayList数据结构

ArrayList的继承关系

  
   
    
     [java] 
     view plain
      copy
     
      
     《java集合03--ArrayList源码分析》
     《java集合03--ArrayList源码分析》
    
   
   
 
  1. java.lang.Object  
  2.    ↳     java.util.AbstractCollection<E>  
  3.          ↳     java.util.AbstractList<E>  
  4.                ↳     java.util.ArrayList<E>  
  5.   
  6. public class ArrayList<E> extends AbstractList<E>  
  7.         implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}  

ArrayList与Collection关系如下图

《java集合03--ArrayList源码分析》

ArrayList包含了两个重要的对象:elementData  size

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

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

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

为了更了解ArrayList的原理,下面对ArrayList源码代码作出分析。ArrayList是通过数组实现的,源码比较容易理解。 

   
    
     
      [java] 
      view plain
       copy
      
       
      《java集合03--ArrayList源码分析》
      《java集合03--ArrayList源码分析》
     
    
    
 
  1.   1 package java.util;  
  2.   2   
  3.   3 public class ArrayList<E> extends AbstractList<E>  
  4.   4         implements List<E>, RandomAccess, Cloneable, java.io.Serializable  
  5.   5 {  
  6.   6     // 序列版本号  
  7.   7     private static final long serialVersionUID = 8683452581122892189L;  
  8.   8   
  9.   9     // 保存ArrayList中数据的数组  
  10.  10     private transient Object[] elementData;  
  11.  11   
  12.  12     // ArrayList中实际数据的数量  
  13.  13     private int size;  
  14.  14   
  15.  15     // ArrayList带容量大小的构造函数。  
  16.  16     public ArrayList(int initialCapacity) {  
  17.  17         super();  
  18.  18         if (initialCapacity < 0)  
  19.  19             throw new IllegalArgumentException("Illegal Capacity: "+  
  20.  20                                                initialCapacity);  
  21.  21         // 新建一个数组  
  22.  22         this.elementData = new Object[initialCapacity];  
  23.  23     }  
  24.  24   
  25.  25     // ArrayList构造函数。默认容量是10。  
  26.  26     public ArrayList() {  
  27.  27         this(10);  
  28.  28     }  
  29.  29   
  30.  30     // 创建一个包含collection的ArrayList  
  31.  31     public ArrayList(Collection<? extends E> c) {  
  32.  32         elementData = c.toArray();  
  33.  33         size = elementData.length;  
  34.  34         // c.toArray might (incorrectly) not return Object[] (see 6260652)  
  35.  35         if (elementData.getClass() != Object[].class)  
  36.  36             elementData = Arrays.copyOf(elementData, size, Object[].class);  
  37.  37     }  
  38.  38   
  39.  39   
  40.  40     // 将当前容量值设为 =实际元素个数  
  41.  41     public void trimToSize() {  
  42.  42         modCount++;  
  43.  43         int oldCapacity = elementData.length;  
  44.  44         if (size < oldCapacity) {  
  45.  45             elementData = Arrays.copyOf(elementData, size);  
  46.  46         }  
  47.  47     }  
  48.  48   
  49.  49   
  50.  50     // 确定ArrarList的容量。  
  51.  51     // 若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2 + 1”  
  52.  52     public void ensureCapacity(int minCapacity) {  
  53.  53         // 将“修改统计数”+1  
  54.  54         modCount++;  
  55.  55         int oldCapacity = elementData.length;  
  56.  56         // 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”  
  57.  57         if (minCapacity > oldCapacity) {  
  58.  58             Object oldData[] = elementData;  
  59.  59             int newCapacity = (oldCapacity * 3)/2 + 1;  
  60.  60             if (newCapacity < minCapacity)  
  61.  61                 newCapacity = minCapacity;  
  62.  62             elementData = Arrays.copyOf(elementData, newCapacity);  
  63.  63         }  
  64.  64     }  
  65.  65   
  66.  66     // 添加元素e  
  67.  67     public boolean add(E e) {  
  68.  68         // 确定ArrayList的容量大小  
  69.  69         ensureCapacity(size + 1);  // Increments modCount!!  
  70.  70         // 添加e到ArrayList中  
  71.  71         elementData[size++] = e;  
  72.  72         return true;  
  73.  73     }  
  74.  74   
  75.  75     // 返回ArrayList的实际大小  
  76.  76     public int size() {  
  77.  77         return size;  
  78.  78     }  
  79.  79   
  80.  80     // 返回ArrayList是否包含Object(o)  
  81.  81     public boolean contains(Object o) {  
  82.  82         return indexOf(o) >= 0;  
  83.  83     }  
  84.  84   
  85.  85     // 返回ArrayList是否为空  
  86.  86     public boolean isEmpty() {  
  87.  87         return size == 0;  
  88.  88     }  
  89.  89   
  90.  90     // 正向查找,返回元素的索引值  
  91.  91     public int indexOf(Object o) {  
  92.  92         if (o == null) {  
  93.  93             for (int i = 0; i < size; i++)  
  94.  94             if (elementData[i]==null)  
  95.  95                 return i;  
  96.  96             } else {  
  97.  97                 for (int i = 0; i < size; i++)  
  98.  98                 if (o.equals(elementData[i]))  
  99.  99                     return i;  
  100. 100             }  
  101. 101             return -1;  
  102. 102         }  
  103. 103   
  104. 104         // 反向查找,返回元素的索引值  
  105. 105         public int lastIndexOf(Object o) {  
  106. 106         if (o == null) {  
  107. 107             for (int i = size-1; i >= 0; i--)  
  108. 108             if (elementData[i]==null)  
  109. 109                 return i;  
  110. 110         } else {  
  111. 111             for (int i = size-1; i >= 0; i--)  
  112. 112             if (o.equals(elementData[i]))  
  113. 113                 return i;  
  114. 114         }  
  115. 115         return -1;  
  116. 116     }  
  117. 117   
  118. 118     // 反向查找(从数组末尾向开始查找),返回元素(o)的索引值  
  119. 119     public int lastIndexOf(Object o) {  
  120. 120         if (o == null) {  
  121. 121             for (int i = size-1; i >= 0; i--)  
  122. 122             if (elementData[i]==null)  
  123. 123                 return i;  
  124. 124         } else {  
  125. 125             for (int i = size-1; i >= 0; i--)  
  126. 126             if (o.equals(elementData[i]))  
  127. 127                 return i;  
  128. 128         }  
  129. 129         return -1;  
  130. 130     }  
  131. 131    
  132. 132   
  133. 133     // 返回ArrayList的Object数组  
  134. 134     public Object[] toArray() {  
  135. 135         return Arrays.copyOf(elementData, size);  
  136. 136     }  
  137. 137   
  138. 138     // 返回ArrayList的模板数组。所谓模板数组,即可以将T设为任意的数据类型  
  139. 139     public <T> T[] toArray(T[] a) {  
  140. 140         // 若数组a的大小 < ArrayList的元素个数;  
  141. 141         // 则新建一个T[]数组,数组大小是“ArrayList的元素个数”,并将“ArrayList”全部拷贝到新数组中  
  142. 142         if (a.length < size)  
  143. 143             return (T[]) Arrays.copyOf(elementData, size, a.getClass());  
  144. 144   
  145. 145         // 若数组a的大小 >= ArrayList的元素个数;  
  146. 146         // 则将ArrayList的全部元素都拷贝到数组a中。  
  147. 147         System.arraycopy(elementData, 0, a, 0, size);  
  148. 148         if (a.length > size)  
  149. 149             a[size] = null;  
  150. 150         return a;  
  151. 151     }  
  152. 152   
  153. 153     // 获取index位置的元素值  
  154. 154     public E get(int index) {  
  155. 155         RangeCheck(index);  
  156. 156   
  157. 157         return (E) elementData[index];  
  158. 158     }  
  159. 159   
  160. 160     // 设置index位置的值为element  
  161. 161     public E set(int index, E element) {  
  162. 162         RangeCheck(index);  
  163. 163   
  164. 164         E oldValue = (E) elementData[index];  
  165. 165         elementData[index] = element;  
  166. 166         return oldValue;  
  167. 167     }  
  168. 168   
  169. 169     // 将e添加到ArrayList中  
  170. 170     public boolean add(E e) {  
  171. 171         ensureCapacity(size + 1);  // Increments modCount!!  
  172. 172         elementData[size++] = e;  
  173. 173         return true;  
  174. 174     }  
  175. 175   
  176. 176     // 将e添加到ArrayList的指定位置  
  177. 177     public void add(int index, E element) {  
  178. 178         if (index > size || index < 0)  
  179. 179             throw new IndexOutOfBoundsException(  
  180. 180             "Index: "+index+", Size: "+size);  
  181. 181   
  182. 182         ensureCapacity(size+1);  // Increments modCount!!  
  183. 183         System.arraycopy(elementData, index, elementData, index + 1,  
  184. 184              size - index);  
  185. 185         elementData[index] = element;  
  186. 186         size++;  
  187. 187     }  
  188. 188   
  189. 189     // 删除ArrayList指定位置的元素  
  190. 190     public E remove(int index) {  
  191. 191         RangeCheck(index);  
  192. 192   
  193. 193         modCount++;  
  194. 194         E oldValue = (E) elementData[index];  
  195. 195   
  196. 196         int numMoved = size - index - 1;  
  197. 197         if (numMoved > 0)  
  198. 198             System.arraycopy(elementData, index+1, elementData, index,  
  199. 199                  numMoved);  
  200. 200         elementData[--size] = null// Let gc do its work  
  201. 201   
  202. 202         return oldValue;  
  203. 203     }  
  204. 204   
  205. 205     // 删除ArrayList的指定元素  
  206. 206     public boolean remove(Object o) {  
  207. 207         if (o == null) {  
  208. 208                 for (int index = 0; index < size; index++)  
  209. 209             if (elementData[index] == null) {  
  210. 210                 fastRemove(index);  
  211. 211                 return true;  
  212. 212             }  
  213. 213         } else {  
  214. 214             for (int index = 0; index < size; index++)  
  215. 215             if (o.equals(elementData[index])) {  
  216. 216                 fastRemove(index);  
  217. 217                 return true;  
  218. 218             }  
  219. 219         }  
  220. 220         return false;  
  221. 221     }  
  222. 222   
  223. 223   
  224. 224     // 快速删除第index个元素  
  225. 225     private void fastRemove(int index) {  
  226. 226         modCount++;  
  227. 227         int numMoved = size - index - 1;  
  228. 228         // 从"index+1"开始,用后面的元素替换前面的元素。  
  229. 229         if (numMoved > 0)  
  230. 230             System.arraycopy(elementData, index+1, elementData, index,  
  231. 231                              numMoved);  
  232. 232         // 将最后一个元素设为null  
  233. 233         elementData[--size] = null// Let gc do its work  
  234. 234     }  
  235. 235   
  236. 236     // 删除元素  
  237. 237     public boolean remove(Object o) {  
  238. 238         if (o == null) {  
  239. 239             for (int index = 0; index < size; index++)  
  240. 240             if (elementData[index] == null) {  
  241. 241                 fastRemove(index);  
  242. 242             return true;  
  243. 243             }  
  244. 244         } else {  
  245. 245             // 便利ArrayList,找到“元素o”,则删除,并返回true。  
  246. 246             for (int index = 0; index < size; index++)  
  247. 247             if (o.equals(elementData[index])) {  
  248. 248                 fastRemove(index);  
  249. 249             return true;  
  250. 250             }  
  251. 251         }  
  252. 252         return false;  
  253. 253     }  
  254. 254   
  255. 255     // 清空ArrayList,将全部的元素设为null  
  256. 256     public void clear() {  
  257. 257         modCount++;  
  258. 258   
  259. 259         for (int i = 0; i < size; i++)  
  260. 260             elementData[i] = null;  
  261. 261   
  262. 262         size = 0;  
  263. 263     }  
  264. 264   
  265. 265     // 将集合c追加到ArrayList中  
  266. 266     public boolean addAll(Collection<? extends E> c) {  
  267. 267         Object[] a = c.toArray();  
  268. 268         int numNew = a.length;  
  269. 269         ensureCapacity(size + numNew);  // Increments modCount  
  270. 270         System.arraycopy(a, 0, elementData, size, numNew);  
  271. 271         size += numNew;  
  272. 272         return numNew != 0;  
  273. 273     }  
  274. 274   
  275. 275     // 从index位置开始,将集合c添加到ArrayList  
  276. 276     public boolean addAll(int index, Collection<? extends E> c) {  
  277. 277         if (index > size || index < 0)  
  278. 278             throw new IndexOutOfBoundsException(  
  279. 279             "Index: " + index + ", Size: " + size);  
  280. 280   
  281. 281         Object[] a = c.toArray();  
  282. 282         int numNew = a.length;  
  283. 283         ensureCapacity(size + numNew);  // Increments modCount  
  284. 284   
  285. 285         int numMoved = size - index;  
  286. 286         if (numMoved > 0)  
  287. 287             System.arraycopy(elementData, index, elementData, index + numNew,  
  288. 288                  numMoved);  
  289. 289   
  290. 290         System.arraycopy(a, 0, elementData, index, numNew);  
  291. 291         size += numNew;  
  292. 292         return numNew != 0;  
  293. 293     }  
  294. 294   
  295. 295     // 删除fromIndex到toIndex之间的全部元素。  
  296. 296     protected void removeRange(int fromIndex, int toIndex) {  
  297. 297     modCount++;  
  298. 298     int numMoved = size - toIndex;  
  299. 299         System.arraycopy(elementData, toIndex, elementData, fromIndex,  
  300. 300                          numMoved);  
  301. 301   
  302. 302     // Let gc do its work  
  303. 303     int newSize = size - (toIndex-fromIndex);  
  304. 304     while (size != newSize)  
  305. 305         elementData[--size] = null;  
  306. 306     }  
  307. 307   
  308. 308     private void RangeCheck(int index) {  
  309. 309     if (index >= size)  
  310. 310         throw new IndexOutOfBoundsException(  
  311. 311         "Index: "+index+", Size: "+size);  
  312. 312     }  
  313. 313   
  314. 314   
  315. 315     // 克隆函数  
  316. 316     public Object clone() {  
  317. 317         try {  
  318. 318             ArrayList<E> v = (ArrayList<E>) super.clone();  
  319. 319             // 将当前ArrayList的全部元素拷贝到v中  
  320. 320             v.elementData = Arrays.copyOf(elementData, size);  
  321. 321             v.modCount = 0;  
  322. 322             return v;  
  323. 323         } catch (CloneNotSupportedException e) {  
  324. 324             // this shouldn't happen, since we are Cloneable  
  325. 325             throw new InternalError();  
  326. 326         }  
  327. 327     }  
  328. 328   
  329. 329   
  330. 330     // java.io.Serializable的写入函数  
  331. 331     // 将ArrayList的“容量,所有的元素值”都写入到输出流中  
  332. 332     private void writeObject(java.io.ObjectOutputStream s)  
  333. 333         throws java.io.IOException{  
  334. 334     // Write out element count, and any hidden stuff  
  335. 335     int expectedModCount = modCount;  
  336. 336     s.defaultWriteObject();  
  337. 337   
  338. 338         // 写入“数组的容量”  
  339. 339         s.writeInt(elementData.length);  
  340. 340   
  341. 341     // 写入“数组的每一个元素”  
  342. 342     for (int i=0; i<size; i++)  
  343. 343             s.writeObject(elementData[i]);  
  344. 344   
  345. 345     if (modCount != expectedModCount) {  
  346. 346             throw new ConcurrentModificationException();  
  347. 347         }  
  348. 348   
  349. 349     }  
  350. 350   
  351. 351   
  352. 352     // java.io.Serializable的读取函数:根据写入方式读出  
  353. 353     // 先将ArrayList的“容量”读出,然后将“所有的元素值”读出  
  354. 354     private void readObject(java.io.ObjectInputStream s)  
  355. 355         throws java.io.IOException, ClassNotFoundException {  
  356. 356         // Read in size, and any hidden stuff  
  357. 357         s.defaultReadObject();  
  358. 358   
  359. 359         // 从输入流中读取ArrayList的“容量”  
  360. 360         int arrayLength = s.readInt();  
  361. 361         Object[] a = elementData = new Object[arrayLength];  
  362. 362   
  363. 363         // 从输入流中将“所有的元素值”读出  
  364. 364         for (int i=0; i<size; i++)  
  365. 365             a[i] = s.readObject();  
  366. 366     }  
  367. 367 }  

总结
(01) ArrayList 实际上是通过一个数组去保存数据的。当我们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是10
(02) 当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”
(03) ArrayList的克隆函数,即是将全部元素克隆到一个数组中。
(04) ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

第4部分 ArrayList遍历方式

ArrayList支持3种遍历方式

(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

  
   
    
     [java] 
     view plain
      copy
     
      
     《java集合03--ArrayList源码分析》
     《java集合03--ArrayList源码分析》
    
   
   
 
  1. Integer value = null;  
  2. Iterator iter = list.iterator();  
  3. while (iter.hasNext()) {  
  4.     value = (Integer)iter.next();  
  5. }  

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

  
   
    
     [java] 
     view plain
      copy
     
      
     《java集合03--ArrayList源码分析》
     《java集合03--ArrayList源码分析》
    
   
   
 
  1. Integer value = null;  
  2. int size = list.size();  
  3. for (int i=0; i<size; i++) {  
  4.     value = (Integer)list.get(i);          
  5. }  

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

  
   
    
     [java] 
     view plain
      copy
     
      
     《java集合03--ArrayList源码分析》
     《java集合03--ArrayList源码分析》
    
   
   
 
  1. Integer value = null;  
  2. for (Integer integ:list) {  
  3.     value = integ;  
  4. }  

下面通过一个实例,比较这3种方式的效率,实例代码(ArrayListRandomAccessTest.java)如下:

   
    
     
      [java] 
      view plain
       copy
      
       
      《java集合03--ArrayList源码分析》
      《java集合03--ArrayList源码分析》
     
    
    
 
  1.  1 import java.util.*;  
  2.  2 import java.util.concurrent.*;  
  3.  3   
  4.  4 /* 
  5.  5  * @desc ArrayList遍历方式和效率的测试程序。 
  6.  6  * 
  7.  7  * @author skywang 
  8.  8  */  
  9.  9 public class ArrayListRandomAccessTest {  
  10. 10   
  11. 11     public static void main(String[] args) {  
  12. 12         List list = new ArrayList();  
  13. 13         for (int i=0; i<100000; i++)  
  14. 14             list.add(i);  
  15. 15         //isRandomAccessSupported(list);  
  16. 16         iteratorThroughRandomAccess(list) ;  
  17. 17         iteratorThroughIterator(list) ;  
  18. 18         iteratorThroughFor2(list) ;  
  19. 19       
  20. 20     }  
  21. 21   
  22. 22     private static void isRandomAccessSupported(List list) {  
  23. 23         if (list instanceof RandomAccess) {  
  24. 24             System.out.println("RandomAccess implemented!");  
  25. 25         } else {  
  26. 26             System.out.println("RandomAccess not implemented!");  
  27. 27         }  
  28. 28   
  29. 29     }  
  30. 30   
  31. 31     public static void iteratorThroughRandomAccess(List list) {  
  32. 32   
  33. 33         long startTime;  
  34. 34         long endTime;  
  35. 35         startTime = System.currentTimeMillis();  
  36. 36         for (int i=0; i<list.size(); i++) {  
  37. 37             list.get(i);  
  38. 38         }  
  39. 39         endTime = System.currentTimeMillis();  
  40. 40         long interval = endTime - startTime;  
  41. 41         System.out.println("iteratorThroughRandomAccess:" + interval+" ms");  
  42. 42     }  
  43. 43   
  44. 44     public static void iteratorThroughIterator(List list) {  
  45. 45   
  46. 46         long startTime;  
  47. 47         long endTime;  
  48. 48         startTime = System.currentTimeMillis();  
  49. 49         for(Iterator iter = list.iterator(); iter.hasNext(); ) {  
  50. 50             iter.next();  
  51. 51         }  
  52. 52         endTime = System.currentTimeMillis();  
  53. 53         long interval = endTime - startTime;  
  54. 54         System.out.println("iteratorThroughIterator:" + interval+" ms");  
  55. 55     }  
  56. 56   
  57. 57   
  58. 58     public static void iteratorThroughFor2(List list) {  
  59. 59   
  60. 60         long startTime;  
  61. 61         long endTime;  
  62. 62         startTime = System.currentTimeMillis();  
  63. 63         for(Object obj:list)  
  64. 64             ;  
  65. 65         endTime = System.currentTimeMillis();  
  66. 66         long interval = endTime - startTime;  
  67. 67         System.out.println("iteratorThroughFor2:" + interval+" ms");  
  68. 68     }  
  69. 69 }  

运行结果

iteratorThroughRandomAccess:3 ms
iteratorThroughIterator:8 ms
iteratorThroughFor2:5 ms

由此可见,遍历ArrayList时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低!

第5部分 toArray()异常

当我们调用ArrayList中的 toArray(),可能遇到过抛出“java.lang.ClassCastException”异常的情况。下面我们说说这是怎么回事。

ArrayList提供了2个toArray()函数:

  
   
    
     [java] 
     view plain
      copy
     
      
     《java集合03--ArrayList源码分析》
     《java集合03--ArrayList源码分析》
    
   
   
 
  1. Object[] toArray()  
  2. <T> T[] toArray(T[] contents)  

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

toArray() 会抛出异常是因为 toArray() 返回的是 Object[] 数组,将 Object[] 转换为其它类型(如如,将Object[]转换为的Integer[])则会抛出“java.lang.ClassCastException”异常,因为Java不支持向下转型。具体的可以参考前面ArrayList.java的源码介绍部分的toArray()。
解决该问题的办法是调用 <T> T[] toArray(T[] contents) , 而不是 Object[] toArray()。

调用 toArray(T[] contents) 返回T[]的可以通过以下几种方式实现。

  
   
    
     [java] 
     view plain
      copy
     
      
     《java集合03--ArrayList源码分析》
     《java集合03--ArrayList源码分析》
    
   
   
 
  1. // toArray(T[] contents)调用方式一  
  2. public static Integer[] vectorToArray1(ArrayList<Integer> v) {  
  3.     Integer[] newText = new Integer[v.size()];  
  4.     v.toArray(newText);  
  5.     return newText;  
  6. }  
  7.   
  8. // toArray(T[] contents)调用方式二。最常用!  
  9. public static Integer[] vectorToArray2(ArrayList<Integer> v) {  
  10.     Integer[] newText = (Integer[])v.toArray(new Integer[0]);  
  11.     return newText;  
  12. }  
  13.   
  14. // toArray(T[] contents)调用方式三  
  15. public static Integer[] vectorToArray3(ArrayList<Integer> v) {  
  16.     Integer[] newText = new Integer[v.size()];  
  17.     Integer[] newStrings = (Integer[])v.toArray(newText);  
  18.     return newStrings;  
  19. }  

  上例中的第二种方式可以不使用前面的强制转换就可以运行,还有就是有人讨论后面的匿名的数组申明时,容量使用0好还是使用v.size()好,以下是我个人做的实验,仅供参考

[java] 
view plain
 copy
 
《java集合03--ArrayList源码分析》
《java集合03--ArrayList源码分析》

  1. public static Integer[] vectorToArray2(ArrayList<Integer> v) {  
  2.         Integer[] newText = v.toArray(new Integer[0]);  
  3.         return newText;  
  4.     }  
  5.   
  6.     public static Integer[] vectorToArray1(ArrayList<Integer> v) {  
  7.         Integer[] newText = v.toArray(new Integer[v.size()]);  
  8.         return newText;  
  9.     }  
  10.   
  11.     public static void main(String[] args) {  
  12.         ArrayList<Integer> v = new ArrayList<Integer>();  
  13.         for (int i = 0; i < 100000000; i++) {  
  14.             v.add(1);  
  15.         }  
  16.   
  17.         long aa = System.currentTimeMillis();  
  18.         Integer[] a = vectorToArray2(v);  
  19.         long bb = System.currentTimeMillis();  
  20.   
  21.         Integer[] b = vectorToArray1(v);  
  22.         long cc = System.currentTimeMillis();  
  23.         System.out.print((bb – aa) + ”    “ + (cc – bb));  
  24.         }  

实验数据如下:

实验表明,在容量较小的情况下,两种方式的使用是没有差别的,但是容量增大的时候,使用v.size()申明数组更快,并且两种情况时间差很大,具体原因我认为可能是元素增多以后,new的过程浪费了大量的时间。

第6部分 ArrayList示例

本文通过一个实例(ArrayListTest.java),介绍 ArrayList 中常用API的用法。

[java] 
view plain
 copy
 
《java集合03--ArrayList源码分析》
《java集合03--ArrayList源码分析》

  1.  1 import java.util.*;  
  2.  2   
  3.  3 /* 
  4.  4  * @desc ArrayList常用API的测试程序 
  5.  5  * @author skywang  
  6.  6  * @email kuiwu-wang@163.com 
  7.  7  */  
  8.  8 public class ArrayListTest {  
  9.  9   
  10. 10     public static void main(String[] args) {  
  11. 11           
  12. 12         // 创建ArrayList  
  13. 13         ArrayList list = new ArrayList();  
  14. 14   
  15. 15         // 将“”  
  16. 16         list.add(“1”);  
  17. 17         list.add(“2”);  
  18. 18         list.add(“3”);  
  19. 19         list.add(“4”);  
  20. 20         // 将下面的元素添加到第1个位置  
  21. 21         list.add(0“5”);  
  22. 22   
  23. 23         // 获取第1个元素  
  24. 24         System.out.println(“the first element is: “+ list.get(0));  
  25. 25         // 删除“3”  
  26. 26         list.remove(“3”);  
  27. 27         // 获取ArrayList的大小  
  28. 28         System.out.println(“Arraylist size=: “+ list.size());  
  29. 29         // 判断list中是否包含”3″  
  30. 30         System.out.println(“ArrayList contains 3 is: “+ list.contains(3));  
  31. 31         // 设置第2个元素为10  
  32. 32         list.set(1“10”);  
  33. 33   
  34. 34         // 通过Iterator遍历ArrayList  
  35. 35         for(Iterator iter = list.iterator(); iter.hasNext(); ) {  
  36. 36             System.out.println(“next is: “+ iter.next());  
  37. 37         }  
  38. 38   
  39. 39         // 将ArrayList转换为数组  
  40. 40         String[] arr = (String[])list.toArray(new String[0]);  
  41. 41         for (String str:arr)  
  42. 42             System.out.println(“str: “+ str);  
  43. 43   
  44. 44         // 清空ArrayList  
  45. 45         list.clear();  
  46. 46         // 判断ArrayList是否为空  
  47. 47         System.out.println(“ArrayList is empty: “+ list.isEmpty());  
  48. 48     }  
  49. 49 }  

运行结果

the first element is: 5
Arraylist size=: 4
ArrayList contains 3 is: false
next is: 5
next is: 10
next is: 2
next is: 4
str: 5
str: 10
str: 2
str: 4
ArrayList is empty: true

    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/cfp008/article/details/53130246
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞