ArrayList源码分析

本文详细介绍了Java中的ArrayList类,包括其内部实现、构造函数、主要方法及其工作原理。对比了三种遍历方式的效率,并解决了toArray方法使用中可能出现的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:

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的继承关系

  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构造函数

  1. // 默认构造函数  
  2. ArrayList()  
  3.  
  4. // capacity是ArrayList的默认容量大小。当由于增加数据导致容量不足时,容量会添加上一次容量大小的一半。  
  5. ArrayList(int capacity)  
  6.  
  7. // 创建一个包含collection的ArrayList  
  8. ArrayList(Collection<? extends E> collection) 


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

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


ArrayList支持3种遍历方式

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

  1. Integer value = null;  
  2. Iterator iter = list.iterator();  
  3. while (iter.hasNext()) {  
  4.     value = (Integer)iter.next();  

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

  1. Integer value = null;  
  2. int size = list.size();  
  3. for (int i=0; i<size; i++) {  
  4.     value = (Integer)list.get(i);          

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

  1. Integer value = null;  
  2. for (Integer integ:list) {  
  3.     value = integ;  
其中使用索引的第二种方式效率最高


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

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

  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[]的可以通过以下几种方式实现。

  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;  


资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 在 Linux 系统中,查找域名或主机名对应的 IP 地址是网络管理中的一项基础且关键任务,对于排查网络故障、调试网络问题以及监控网络服务是否正常运行等场景都非常重要。本文将介绍五种在 Linux 终端查询域名 IP 地址的方法。 首先,dig 命令(全称 Domain Information Groper)是一个功能强大的 DNS 查询工具,能够向 DNS 服务器发送查询请求并获取详细的响应信息。如果需要查询单个域名的 IP 地址,可以使用命令 dig 2daygeek.com +short 。此外,还可以通过编写 bash 脚本,将包含域名的文本文件中的域名逐个读取,然后利用 dig 命令进行查询,从而实现批量查询域名 IP 地址的功能。 其次,host 命令是一个简单易用的 DNS 查询工具,主要用于将域名解析为 IP 地址。要获取某个域名的 IP 地址,直接使用 host 2daygeek.com 即可。如果只想显示 IP 地址部分,可以通过管道结合 grep 和 sed 命令来实现,例如:host 2daygeek.com | grep "has address" | sed s/has address/-/g 。 再者,nslookup 命令也是一种常用的 DNS 查询工具,它支持交互式查询 DNS 信息。通过 nslookup 2daygeek.com 可以查询域名的 IP 地址。若要以非交互式的方式只显示 IP 地址,可以使用命令 nslookup 2daygeek.com | awk /^Address:/ {print $2} 。 另外,fping 命令与传统的 ping 命令不同,它不会直接进行 DNS 查询,而是通过发送 ICMP Echo Request(pi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值