源码分析--ArrayList(JDK1.8)
ArrayList是开发常用的有序集合,底层为动态数组实现。可以插入null,并允许重复。
下面是源码中一些比较重要属性:
1、ArrayList默认大小10。
- /**
- * Default initial capacity.
- */
- private static final int DEFAULT_CAPACITY = 10;
2、elementData就是真正存放数据的数组。elementData[]本身是动态的,并不是数组的全部空间都会使用,所以加上transient关键词进行修饰,防止自动序列化。
- transient Object[] elementData; // non-private to simplify nested class access
3、ArrayList的实际大小。每次进行add或者remove后,都会进行跟踪修订。
- /**
- * The size of the ArrayList (the number of elements it contains).
- *
- * @serial
- */
- private int size;
下面分析主要方法:
1、add()方法有两个实现,一种是直接添加,一种是指定index添加。
直接添加代码如下:
- /**
- * Appends the specified element to the end of this list.
- *
- * @param e element to be appended to this list
- * @return <tt>true</tt> (as specified by {@link Collection#add})
- */
- public boolean add(E e) {
- ensureCapacityInternal(size + 1); // Increments modCount!!
- elementData[size++] = e;
- return true;
- }
- 扩容判断
- 元素插入elementData[]尾部,size加1
指定index添加方式:
- public void add(int index, E element) {
- rangeCheckForAdd(index);
- ensureCapacityInternal(size + 1); // Increments modCount!!
- System.arraycopy(elementData, index, elementData, index + 1,
- size - index);
- elementData[index] = element;
- size++;
- }
- 根据当前size,判断指定索引是否合理
- 扩容判断
- 将原数组中从index往后的全部元素copy到index+1之后的位置。也就是把后续元素的索引全部+1
- 需插入的元素放入指定index
- size加1
add()方法中,数组扩容调用的最终方法如下:
- private void grow(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- // minCapacity is usually close to size, so this is a win:
- elementData = Arrays.copyOf(elementData, newCapacity);
- }
代码中看得出,ArrayList会在原先容量的基础上,扩容为原来的1.5倍(oldCapacity + (oldCapacity >> 1)),最大容量为Integer.MAX_VALUE。elementData也就是一个数组复制的过程了。所以在平常的开发中,实例化ArrayList时,可以尽量指定容量大小,减少扩容带来的数组复制开销。
2、remove()方法和add()类似,这里就只简单看下:
- public E remove(int index) {
- rangeCheck(index);
- modCount++;
- E oldValue = elementData(index);
- int numMoved = size - index - 1;
- if (numMoved > 0)
- System.arraycopy(elementData, index+1, elementData, index,
- numMoved);
- elementData[--size] = null; // clear to let GC do its work
- return oldValue;
- }
也就是拿到删除元素的index后,用数组复制的方式进行元素的覆盖。最后一个elementData数组的元素就是成了垃圾数据,让GC进行回收。size减1。
3、序列化
- /**
- * Save the state of the <tt>ArrayList</tt> instance to a stream (that
- * is, serialize it).
- *
- * @serialData The length of the array backing the <tt>ArrayList</tt>
- * instance is emitted (int), followed by all of its elements
- * (each an <tt>Object</tt>) in the proper order.
- */
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException{
- // Write out element count, and any hidden stuff
- int expectedModCount = modCount;
- s.defaultWriteObject();
- // Write out size as capacity for behavioural compatibility with clone()
- s.writeInt(size);
- // Write out all elements in the proper order.
- for (int i=0; i<size; i++) {
- s.writeObject(elementData[i]);
- }
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
- /**
- * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
- * deserialize it).
- */
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- elementData = EMPTY_ELEMENTDATA;
- // Read in size, and any hidden stuff
- s.defaultReadObject();
- // Read in capacity
- s.readInt(); // ignored
- if (size > 0) {
- // be like clone(), allocate array based upon size not capacity
- int capacity = calculateCapacity(elementData, size);
- SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
- ensureCapacityInternal(size);
- Object[] a = elementData;
- // Read in all elements in the proper order.
- for (int i=0; i<size; i++) {
- a[i] = s.readObject();
- }
- }
- }
ArrayList是用动态数组elementData进行数据存储的,所以本身自定义了序列化与反序列化方法。当对象中自定义了 writeObject 和 readObject 方法时,JVM 会调用这两个自定义方法来实现序列化与反序列化。ArrayList只序列化elementData里面的数据。
源码分析--ArrayList(JDK1.8)的更多相关文章
- HashMap 源码分析 基于jdk1.8分析
HashMap 源码分析 基于jdk1.8分析 1:数据结构: transient Node<K,V>[] table; //这里维护了一个 Node的数组结构: 下面看看Node的数 ...
- 【JDK】JDK源码分析-ArrayList
概述 ArrayList 是 List 接口的一个实现类,也是 Java 中最常用的容器实现类之一,可以把它理解为「可变数组」. 我们知道,Java 中的数组初始化时需要指定长度,而且指定后不能改变. ...
- LinkedList源码分析(jdk1.8)
LinkedList概述 LinkedList 是 Java 集合框架中一个重要的实现,我们先简述一下LinkedList的一些特点: LinkedList底层采用的双向链表结构: LinkedL ...
- [源码分析]ArrayList和LinkedList如何实现的?我看你还有机会!
文章已经收录在 Github.com/niumoo/JavaNotes ,更有 Java 程序员所需要掌握的核心知识,欢迎Star和指教. 欢迎关注我的公众号,文章每周更新. 前言 说真的,在 Jav ...
- HashMap实现原理及源码分析(JDK1.7)
转载:https://www.cnblogs.com/chengxiao/p/6059914.html 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技 ...
- CopyOnWriteArrayList 源码分析 基于jdk1.8
CopyOnWriteArrayList 源码分析: 1:成员属性: final transient ReentrantLock lock = new ReentrantLock(); //内部是 ...
- ArrayList 源码分析(JDK1.8)
ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAccess ...
- ArrayList源码分析(JDK1.8)
概述 ArrayList底层是基于数组实现的,并且支持动态扩容的动态数组(变长的集合类).ArrayList允许空值和重复的元素,当向ArrayList中添加元素数量大于其底层数组容量时,会通过扩容机 ...
- JDK源码分析 – ArrayList
ArrayList类的申明 ArrayList是一个支持泛型的,底层通过数组实现的一个可以存任意类型的数据结构,源码中的定义如下: public class ArrayList<E> ex ...
随机推荐
- neo4j传参
py2neo_graph= py2neo.Graph("http://****", user="****", password="*****" ...
- @ResponseBody和@RestController
Spring 关于ResponseBody注解的作用 responseBody一般是作用在方法上的,加上该注解表示该方法的返回结果直接写到Http response Body中,常用在ajax异步请求 ...
- 【ElasticSearch】概念
小史是一个非科班的程序员,虽然学的是电子专业,但是通过自己的努力成功通过了面试,现在要开始迎接新生活了. 对小史面试情况感兴趣的同学可以观看面试现场系列. 随着央视诗词大会的热播,小史开始对诗词感兴趣 ...
- CKEditor粘贴图片上传功能
很多时候我们用一些管理系统的时候,发布新闻.公告等文字类信息时,希望能很快的将word里面的内容直接粘贴到富文本编辑器里面,然后发布出来.减少排版复杂的工作量. 下面是借用百度doc 来快速实现这个w ...
- Seek the Name, Seek the Fame (poj2752
Seek the Name, Seek the Fame Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 14561 Ac ...
- 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); ...
- drawArc
1) 画笔设置 Paint.Style.STROKE 中空模式 paint = new Paint(); //新建一个画笔对象 paint.setAntiAlias(true);//抗锯齿功能 pai ...
- spash和selenium浅析
Splash是什么: Splash是一个Javascript渲染服务.它是一个实现了HTTP API的轻量级浏览器,Splash是用Python实现的,同时使用Twisted和QT.Twisted(Q ...
- 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 ...
- HTML--JS 随机背景色
<html> <head> <title>背景随机变色</title> <script type="text/javascript&qu ...