ArrayList是开发常用的有序集合,底层为动态数组实现。可以插入null,并允许重复。

  下面是源码中一些比较重要属性:

  1、ArrayList默认大小10。

  1. /**
  2. * Default initial capacity.
  3. */
  4. private static final int DEFAULT_CAPACITY = 10;

  

  2、elementData就是真正存放数据的数组。elementData[]本身是动态的,并不是数组的全部空间都会使用,所以加上transient关键词进行修饰,防止自动序列化。

  1. transient Object[] elementData; // non-private to simplify nested class access

  

  3、ArrayList的实际大小。每次进行add或者remove后,都会进行跟踪修订。

  1. /**
  2. * The size of the ArrayList (the number of elements it contains).
  3. *
  4. * @serial
  5. */
  6. private int size;

  下面分析主要方法:

  1、add()方法有两个实现,一种是直接添加,一种是指定index添加。

  直接添加代码如下:

  1. /**
  2. * Appends the specified element to the end of this list.
  3. *
  4. * @param e element to be appended to this list
  5. * @return <tt>true</tt> (as specified by {@link Collection#add})
  6. */
  7. public boolean add(E e) {
  8. ensureCapacityInternal(size + 1); // Increments modCount!!
  9. elementData[size++] = e;
  10. return true;
  11. }
  • 扩容判断
  • 元素插入elementData[]尾部,size加1

  

  指定index添加方式:

  1. public void add(int index, E element) {
  2. rangeCheckForAdd(index);
  3.  
  4. ensureCapacityInternal(size + 1); // Increments modCount!!
  5. System.arraycopy(elementData, index, elementData, index + 1,
  6. size - index);
  7. elementData[index] = element;
  8. size++;
  9. }
  • 根据当前size,判断指定索引是否合理
  • 扩容判断
  • 将原数组中从index往后的全部元素copy到index+1之后的位置。也就是把后续元素的索引全部+1
  • 需插入的元素放入指定index
  • size加1

  add()方法中,数组扩容调用的最终方法如下:

  1. private void grow(int minCapacity) {
  2. // overflow-conscious code
  3. int oldCapacity = elementData.length;
  4. int newCapacity = oldCapacity + (oldCapacity >> 1);
  5. if (newCapacity - minCapacity < 0)
  6. newCapacity = minCapacity;
  7. if (newCapacity - MAX_ARRAY_SIZE > 0)
  8. newCapacity = hugeCapacity(minCapacity);
  9. // minCapacity is usually close to size, so this is a win:
  10. elementData = Arrays.copyOf(elementData, newCapacity);
  11. }

  代码中看得出,ArrayList会在原先容量的基础上,扩容为原来的1.5倍(oldCapacity + (oldCapacity >> 1)),最大容量为Integer.MAX_VALUE。elementData也就是一个数组复制的过程了。所以在平常的开发中,实例化ArrayList时,可以尽量指定容量大小,减少扩容带来的数组复制开销。

  2、remove()方法和add()类似,这里就只简单看下:

  1. public E remove(int index) {
  2. rangeCheck(index);
  3.  
  4. modCount++;
  5. E oldValue = elementData(index);
  6.  
  7. int numMoved = size - index - 1;
  8. if (numMoved > 0)
  9. System.arraycopy(elementData, index+1, elementData, index,
  10. numMoved);
  11. elementData[--size] = null; // clear to let GC do its work
  12.  
  13. return oldValue;
  14. }

  也就是拿到删除元素的index后,用数组复制的方式进行元素的覆盖。最后一个elementData数组的元素就是成了垃圾数据,让GC进行回收。size减1。

  

  3、序列化

  1. /**
  2. * Save the state of the <tt>ArrayList</tt> instance to a stream (that
  3. * is, serialize it).
  4. *
  5. * @serialData The length of the array backing the <tt>ArrayList</tt>
  6. * instance is emitted (int), followed by all of its elements
  7. * (each an <tt>Object</tt>) in the proper order.
  8. */
  9. private void writeObject(java.io.ObjectOutputStream s)
  10. throws java.io.IOException{
  11. // Write out element count, and any hidden stuff
  12. int expectedModCount = modCount;
  13. s.defaultWriteObject();
  14.  
  15. // Write out size as capacity for behavioural compatibility with clone()
  16. s.writeInt(size);
  17.  
  18. // Write out all elements in the proper order.
  19. for (int i=0; i<size; i++) {
  20. s.writeObject(elementData[i]);
  21. }
  22.  
  23. if (modCount != expectedModCount) {
  24. throw new ConcurrentModificationException();
  25. }
  26. }
  27.  
  28. /**
  29. * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
  30. * deserialize it).
  31. */
  32. private void readObject(java.io.ObjectInputStream s)
  33. throws java.io.IOException, ClassNotFoundException {
  34. elementData = EMPTY_ELEMENTDATA;
  35.  
  36. // Read in size, and any hidden stuff
  37. s.defaultReadObject();
  38.  
  39. // Read in capacity
  40. s.readInt(); // ignored
  41.  
  42. if (size > 0) {
  43. // be like clone(), allocate array based upon size not capacity
  44. int capacity = calculateCapacity(elementData, size);
  45. SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
  46. ensureCapacityInternal(size);
  47.  
  48. Object[] a = elementData;
  49. // Read in all elements in the proper order.
  50. for (int i=0; i<size; i++) {
  51. a[i] = s.readObject();
  52. }
  53. }
  54. }

  ArrayList是用动态数组elementData进行数据存储的,所以本身自定义了序列化与反序列化方法。当对象中自定义了 writeObject 和 readObject 方法时,JVM 会调用这两个自定义方法来实现序列化与反序列化。ArrayList只序列化elementData里面的数据。

源码分析--ArrayList(JDK1.8)的更多相关文章

  1. HashMap 源码分析 基于jdk1.8分析

    HashMap 源码分析  基于jdk1.8分析 1:数据结构: transient Node<K,V>[] table;  //这里维护了一个 Node的数组结构: 下面看看Node的数 ...

  2. 【JDK】JDK源码分析-ArrayList

    概述 ArrayList 是 List 接口的一个实现类,也是 Java 中最常用的容器实现类之一,可以把它理解为「可变数组」. 我们知道,Java 中的数组初始化时需要指定长度,而且指定后不能改变. ...

  3. LinkedList源码分析(jdk1.8)

    LinkedList概述 ​ LinkedList 是 Java 集合框架中一个重要的实现,我们先简述一下LinkedList的一些特点: LinkedList底层采用的双向链表结构: LinkedL ...

  4. [源码分析]ArrayList和LinkedList如何实现的?我看你还有机会!

    文章已经收录在 Github.com/niumoo/JavaNotes ,更有 Java 程序员所需要掌握的核心知识,欢迎Star和指教. 欢迎关注我的公众号,文章每周更新. 前言 说真的,在 Jav ...

  5. HashMap实现原理及源码分析(JDK1.7)

    转载:https://www.cnblogs.com/chengxiao/p/6059914.html 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技 ...

  6. CopyOnWriteArrayList 源码分析 基于jdk1.8

    CopyOnWriteArrayList  源码分析: 1:成员属性: final transient ReentrantLock lock = new ReentrantLock();  //内部是 ...

  7. ArrayList 源码分析(JDK1.8)

    ArrayList简介  ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAccess ...

  8. ArrayList源码分析(JDK1.8)

    概述 ArrayList底层是基于数组实现的,并且支持动态扩容的动态数组(变长的集合类).ArrayList允许空值和重复的元素,当向ArrayList中添加元素数量大于其底层数组容量时,会通过扩容机 ...

  9. JDK源码分析 – ArrayList

    ArrayList类的申明 ArrayList是一个支持泛型的,底层通过数组实现的一个可以存任意类型的数据结构,源码中的定义如下: public class ArrayList<E> ex ...

随机推荐

  1. neo4j传参

    py2neo_graph= py2neo.Graph("http://****", user="****", password="*****" ...

  2. @ResponseBody和@RestController

    Spring 关于ResponseBody注解的作用 responseBody一般是作用在方法上的,加上该注解表示该方法的返回结果直接写到Http response Body中,常用在ajax异步请求 ...

  3. 【ElasticSearch】概念

    小史是一个非科班的程序员,虽然学的是电子专业,但是通过自己的努力成功通过了面试,现在要开始迎接新生活了. 对小史面试情况感兴趣的同学可以观看面试现场系列. 随着央视诗词大会的热播,小史开始对诗词感兴趣 ...

  4. CKEditor粘贴图片上传功能

    很多时候我们用一些管理系统的时候,发布新闻.公告等文字类信息时,希望能很快的将word里面的内容直接粘贴到富文本编辑器里面,然后发布出来.减少排版复杂的工作量. 下面是借用百度doc 来快速实现这个w ...

  5. Seek the Name, Seek the Fame (poj2752

    Seek the Name, Seek the Fame Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 14561   Ac ...

  6. How to not show unnecessary zeros when given integers but still have float answers when needed

    NSString *str = [NSString stringWithFormat:@"%g",12.10]; NSLog(@"str = %@",str); ...

  7. drawArc

    1) 画笔设置 Paint.Style.STROKE 中空模式 paint = new Paint(); //新建一个画笔对象 paint.setAntiAlias(true);//抗锯齿功能 pai ...

  8. spash和selenium浅析

    Splash是什么: Splash是一个Javascript渲染服务.它是一个实现了HTTP API的轻量级浏览器,Splash是用Python实现的,同时使用Twisted和QT.Twisted(Q ...

  9. Entity Framework Code First (五)Fluent API - 配置关系 转载 https://www.cnblogs.com/panchunting/p/entity-framework-code-first-fluent-api-configuring-relationships.html

    上一篇文章我们讲解了如何用 Fluent API 来配置/映射属性和类型,本文将把重点放在其是如何配置关系的. 文中所使用代码如下 public class Student { public int ...

  10. HTML--JS 随机背景色

    <html> <head> <title>背景随机变色</title> <script type="text/javascript&qu ...