在端午节这个节日里,有一个特殊的任务,我带着你一起揭开“ArrayList”的真面目。从成员变量、构造函数、主要方法三部分,对ArrayList有进一步的认识,希望能够帮助你。

一、成员变量

  1.   //默认容量
  2. private static final int DEFAULT_CAPACITY = 10;
  3. //空数组,当调用无参数构造函数的时候默认给个空数组
  4. private static final Object[] EMPTY_ELEMENTDATA = {};
  5. //真正保存数据的数组
  6. private transient Object[] elementData;
  7. //数组的大小
  8. private int size;

transient关键字:ArrayList实现了Serializable接口,而添加上transient关键字,则elementData对象就不可以序列化。

二、构造函数

  • 无参构造方法

  • 带有容量的构造方法

  • 带参数Collection的构造方法

在参数Collection的构造方法中,只有当当得到的elementData的类名不是Object,才会执行复制操作,因为Java是动态绑定,所以getClass获取的并不一定是Object类型,有可能是它的子类。

  1. /**
  2. * 初始化elementData
  3. * @param initialCapacity
  4. */
  5. public ArrayList(int initialCapacity) {
  6. super();
  7. //如果小于0,则抛出异常
  8. if (initialCapacity < 0)
  9. throw new IllegalArgumentException("Illegal Capacity: "+
  10. initialCapacity);
  11. //初始化elementData数组
  12. this.elementData = new Object[initialCapacity];
  13. }
  14.  
  15. /**
  16. * 初始化为空的对象数组
  17. */
  18. public ArrayList() {
  19. super();
  20. this.elementData = EMPTY_ELEMENTDATA;
  21. }
  22.  
  23. public ArrayList(Collection<? extends E> c) {
  24. //将c容器转换为object类型的数组
  25. elementData = c.toArray();
  26. //更新size的大小
  27. size = elementData.length;
  28. //当得到的elementData的类名不是Object,才会执行复制操作
  29. if (elementData.getClass() != Object[].class)
  30. elementData = Arrays.copyOf(elementData, size, Object[].class);
  31. }

三、主要方法

1、add方法

  1. //添加元素
  2. public boolean add(E e) {
  3. //首先判断数组容量是否需要扩充
  4. ensureCapacityInternal(size + 1); // Increments modCount!!
  5. //添加元素,更新size的大小
  6. elementData[size++] = e;
  7. return true;
  8. }

ArrayList相当于在没指定initialCapacity时就是会使用延迟分配对象数组空间,当第一次插入元素时ensureCapacityInternal,才分配10个对象空间。

2、get方法

  1. //通过下标获取元素
  2. public E get(int index) {
  3. //判断下标的合理性
  4. rangeCheck(index);
  5. //返回元素
  6. return elementData(index);
  7. }

3、remove方法

在remove方法中,我们需要注意对null的特殊处理。

  1. public boolean remove(Object o) {
  2. //如果为null对象,则特殊处理,使用==来判断
  3. if (o == null) {
  4. for (int index = 0; index < size; index++)
  5. if (elementData[index] == null) {
  6. fastRemove(index);
  7. return true;
  8. }
  9. } else {
  10. //如果不为null,则使用equals方法来判断。
  11. for (int index = 0; index < size; index++)
  12. if (o.equals(elementData[index])) {
  13. fastRemove(index);
  14. return true;
  15. }
  16. }
  17. return false;
  18. }

四、其他常用的方法

removeAll:移除集合A和集合B的交集,即A-B。

retainAll:保留两个集合的交集。

五、ArrayList的大小是如何自动增加的?(面试题)

  • ensureCapacityInternal    是判断是否要扩容的方法

  • ensureExplicitCapacity

  • grow 具体的扩容方法

实现思想:

  1. 确定所需minCapacity和数组当前size的关系,如果minCapacity>size,则准备grow。

  2. 如果1.5size<minCapacity,则准备扩充为minCapacity。

  3. minCapacity和MAX_ARRAY_SIZE 的关系,如果minCapacity>MAX_ARRAY_SIZE ,则需要判断minCapacity是否超出int类型所能表示的最大值。如果超出,则抛出OutOfMemoryError。

  1. //确保数组能够存放的:minCapacity
  2. private void ensureCapacityInternal(int minCapacity) {
  3. //如果elementData是空对象数组,最小容量为minCapacity和DEFAULT_CAPACITY最大值
  4. if (elementData == EMPTY_ELEMENTDATA) {
  5. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  6. }
  7. //判断是否需要扩容
  8. ensureExplicitCapacity(minCapacity);
  9. }
  10.  
  11. private void ensureExplicitCapacity(int minCapacity) {
  12. //增加被改变的次数
  13. modCount++;
  14. // 最小容量大于elementData的长度,则需要扩充
  15. if (minCapacity - elementData.length > 0)
  16. grow(minCapacity);
  17. }
  18.  
  19. //数组的最大上限
  20. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  21.  
  22. private void grow(int minCapacity) {
  23. // 数组原来的长度,保存副本
  24. int oldCapacity = elementData.length;
  25. //扩容至原来的1.5倍
  26. int newCapacity = oldCapacity + (oldCapacity >> 1);
  27. //判断新容量是否够用,如果不够则赋值为minCapacity
  28. if (newCapacity - minCapacity < 0)
  29. newCapacity = minCapacity;
  30. //如果newCapacity超过MAX_ARRAY_SIZE
  31. if (newCapacity - MAX_ARRAY_SIZE > 0)
  32. //检查容量的int值是不是已经溢出。
  33. newCapacity = hugeCapacity(minCapacity);
  34. // 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间
  35. // 并将elementData的数据复制到新的内存空间
  36. elementData = Arrays.copyOf(elementData, newCapacity);
  37. }
  38.  
  39. private static int hugeCapacity(int minCapacity) {
  40. if (minCapacity < 0) // overflow
  41. throw new OutOfMemoryError();
  42. return (minCapacity > MAX_ARRAY_SIZE) ?
  43. Integer.MAX_VALUE :
  44. MAX_ARRAY_SIZE;
  45. }

欢迎加入Java学习交流群点击:484757838 

ArrayList源码解读的更多相关文章

  1. ArrayList 源码解读

    ArrayList 源码解读     基于JDk 1.7.0_80 public class ArrayList<E> extends AbstractList<E> impl ...

  2. JDK12下的ArrayList源码解读 与 Vector的对比

    ArrayList源码阅读. //测试代码实现如下 private static void arrayList() { ArrayList<String> list = new Array ...

  3. ArrayList源码解读(jdk1.8)

    概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解Arra ...

  4. 深入理解JAVA集合系列四:ArrayList源码解读

    在开始本章内容之前,这里先简单介绍下List的相关内容. List的简单介绍 有序的collection,用户可以对列表中每个元素的插入位置进行精确的控制.用户可以根据元素的整数索引(在列表中的位置) ...

  5. Java集合ArrayList源码解读

    最近在回顾数据结构,想到JDK这样好的代码资源不利用有点可惜,这是第一篇,花了心思.篇幅有点长,希望想看的朋友认真看下去,提出宝贵的意见.  :) 内部原理 ArrayList 的3个字段 priva ...

  6. java集合之ArrayList源码解读

    源自:jdk1.8.0_121 ArrayList继承自AbstractList,实现了List.RandomAccess.Cloneable.Serializable. ArrayList内部是通过 ...

  7. ArrayList源码解读笔记

    简介: ArrayList是我们开发中非常常用的数据存储容器之一,其底层是数组实现的,我们可以在集合中存储任意类型的数据,ArrayList是线程不安全的,非常适合用于对元素进行查找,效率非常高. 线 ...

  8. Java集合(四)--基于JDK1.8的ArrayList源码解读

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...

  9. jdk1.8.0_45源码解读——ArrayList的实现

    jdk1.8.0_45源码解读——ArrayList的实现 一.ArrayList概述 ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素. ...

随机推荐

  1. 腾讯云上Selenium用法示例

    欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 作者:崔庆才 前言 在上一节我们学习了PhantomJS 的基本用法,归根结底它是一个没有界面的浏览器,而且运 ...

  2. php面向对象(一)---2017-04-17

    重点:定义类与实例化类:访问修饰符:构造函数 一.面向对象 面向对于与面向过程的主要区别在于:前者包含类和对象的概念 二.类和对象   1.类是由众多对象抽象(归纳总结)出来的东西  代表所有对象的特 ...

  3. IEnumerable<T>和IQueryable<T>

    建议29.区别LINQ查询中的IEnumerable<T>和IQueryable<T> LINQ查询方法一共提供了两类扩展方法,在System.Linq命名空间下,有两个静态类 ...

  4. jdk源码剖析五:JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

    目录 1.背景 2.为什么废弃永久代(PermGen) 3.深入理解元空间(Metaspace) 4.总结 ========正文分割线===== 一.背景 1.1 永久代(PermGen)在哪里? 根 ...

  5. cas错误:org.jasig.cas.client.validation.TicketValidationException: No principal was found in the response from the CAS server.

    这个问题困扰了我好几天,最终被这个哥们解决了,具体请参考:http://www.oschina.net/question/252484_149958?sort=time

  6. mui开发app之webview是什么

    WebView(网络视图)能加载显示网页,可以将其视为一个浏览器,webview被封装在html5+,plus对象中,底层由java,OC实现. 先来谈谈我对webview的理解: 使用mui开发的a ...

  7. poj3320尺取法

    Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is co ...

  8. Java AOP (1) compile time weaving 【Java 切面编程 (1) 编译期织入】

    According to wikipedia  aspect-oriented programming (AOP) is a programming paradigm that aims to inc ...

  9. Scrollview中嵌套ListView(自定义组件解决)

    首先,ScrollView中只能放一个控件,一般都放LinearLayout,orientation属性值为vertical.在LinearLayout中放需要呈现的内容.ListView也在其中,L ...

  10. Spring boot 默认静态资源路径与手动配置访问路径

    在application.propertis中配置 ##端口号server.port=8081 ##默认前缀spring.mvc.view.prefix=/## 响应页面默认后缀spring.mvc. ...