Java 集合系列(二)ArrayList详解

ArrayList

ArrayList 是通过一个数组来实现的,因此它是在连续的存储位置存放对象的引用,只不过它比 Array 更智能,能够根据集合长度进行自动扩容。

假设让我们来实现一个简单的能够自动扩容的数组,我们最容易想到的点就是:

  1. add()的时候需要判断当前数组size+1是否等于此时定义的数组大小;
  2. 若小于直接添加即可;否则,需要先扩容再进行添加。

实际上,ArrayList的内部实现原理也是这样子,我们可以来研究分析一下ArrayList的源码

add(E e) 源码分析

/**
   * 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);  // 进行扩容校验
    elementData[size++] = e;      // 将值添加到数组后面,并将 size+1
    return true;
  }

  /**
   * The array buffer into which the elements of the ArrayList are stored.
   * The capacity of the ArrayList is the length of this array buffer. Any
   * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
   * will be expanded to DEFAULT_CAPACITY when the first element is added.
   */
  transient Object[] elementData; // non-private to simplify nested class access

  private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));  // elementData 数组
  }

  /**
   * Default initial capacity.
   */
  private static final int DEFAULT_CAPACITY = 10;

  /**
   * Shared empty array instance used for default sized empty instances. We
   * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
   * first element is added.
   */
  private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

  // 返回最大的 index
  private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {  // 与空数组实例对比
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
  }

  private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
  }

扩容调用方法,实际也就是数组复制的过程

/**
   * Increases the capacity to ensure that it can hold at least the
   * number of elements specified by the minimum capacity argument.
   *
   * @param minCapacity the desired minimum capacity
   */
  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);
  }

add(int index, E element) 源码分析

/**
   * Inserts the specified element at the specified position in this
   * list. Shifts the element currently at that position (if any) and
   * any subsequent elements to the right (adds one to their indices).
   *
   * @param index index at which the specified element is to be inserted
   * @param element element to be inserted
   * @throws IndexOutOfBoundsException {@inheritDoc}
   */
  public void add(int index, E element) {
    rangeCheckForAdd(index);  // 校验index是否超过当前定义的数组大小范围,超过则抛出 IndexOutOfBoundsException

    ensureCapacityInternal(size + 1); // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
             size - index);   // 复制,向后移动
    elementData[index] = element;
    size++;
  }

  /**
   * A version of rangeCheck used by add and addAll.
   */
  private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
      throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
  }

从上面的源码分析可知,扩容和随机插入元素的消耗比较大,因此在实际开发中,应尽量指定ArrayList大小,减少在随机插入操作。

优缺点

优点

  1. 封装了一个动态再分配的对象数组
  2. 使用索引进行随机访问效率高

缺陷

  1. 在数组中增删一个元素,所有元素都要往后往前移动,效率低下

知识脑图

以上所述是小编给大家介绍的Java集合系列ArrayList详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 微信小程序实现获取小程序码和二维码java接口开发

    前言:目前小程序推出了自己的识别码,小程序码,这个圆形的码看起来比二维码好看.本文总结微信小程序的获取小程序码和二维码并生成二维码图片的接口开发.主要内容摘抄自微信小程序的API文档,java接口开发是自己总结开发. 微信小程序API文档:获取二维码 一.简介 通过后台接口可以获取小程序任意页面的二维码,扫描该二维码可以直接进入小程序对应的页面.目前微信支持两种二维码,小程序码(左),小程序二维码(右),如下所示: 二.获取小程序码 目前有两个接口可以生成小程序码,开发者可以根据自己的需要选择合

  • 利用weixin-java-miniapp生成小程序码并直接返回图片文件流的方法

    有时候我们可能需要在其他的网页上展示我们自己的小程序中某些页面的小程序码,这种时候,我们需要用到小程序的生成小程序码的相关接口. 工具选型 我们仍然选用简单方便的weixin-java-miniapp来完成此功能. 项目配置 详见我们的另一篇文章点此进入 生成小程序码的相关类型 小程序码的其他生成方式以及相关类型在这篇文章点此进入中介绍的较为详细,此处不再赘述,以下仅以生成不限制张数的这种类型来做一个示例. 生成小程序码图片 先获取小程序的service实例wxMaService. 再获取二维码

  • 详解java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)

    1.序列化实现 public class CloneUtils { @SuppressWarnings("unchecked") public static <T extends Serializable> T clone(T object){ T cloneObj = null; try { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream obs = new Objec

  • Java在利用反射条件下替换英文字母中的值

    Java在利用反射条件下替换英文字母中的值 (1)创建两个Class: ReflectTest类如下: package cn.itcast.day01; import java.lang.reflect.Constructor; import java.lang.reflect.Field; public class ReflectTest { public static void main(String[] args) throws Exception { changeStringValue(

  • 拳皇(Java简单的小程序)代码实例

    刚开始学习Java,看完老九君的视频根据他的内容敲的代码,感觉还挺有成就感的,毕竟刚学习Java. package helloasd;import java.util.*; public class hellojava { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.print("输入名称: "); //用户自己输入名字 String userna

  • JAVA线程池原理实例详解

    本文实例讲述了JAVA线程池原理.分享给大家供大家参考,具体如下: 线程池的优点 1.线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用. 2.可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃. 线程池的创建 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQu

  • 详解Java发送HTTP请求

    前言 请求http的Demo是个人亲测过,目前该方式已经在线上运行着.因为是http请求,所有发送post 和get 请求的demo都有在下方贴出,包括怎么测试,大家可直接 copy到自己的项目中使用. 正文 使用须知 为了避免大家引错包我把依赖和涉及到包路径给大家 import java.net.HttpURLConnection; import java.net.URI; import org.apache.http.HttpResponse; import org.apache.http.

  • 作为程序员必须掌握的Java虚拟机中的22个重难点(推荐0

    Java虚拟机一直是比较重要的知识点,是Java高级开发必会的.本文为你总结了关于JVM的22个重点.难点,图文并茂的向你展示和JVM有关的重点知识.全文共7000字左右. 概念 虚拟机:指以软件的方式模拟具有完整硬件系统功能.运行在一个完全隔离环境中的完整计算机系统 ,是物理机的软件实现.常用的虚拟机有VMWare,Visual Box,Java Virtual Machine(Java虚拟机,简称JVM). Java虚拟机阵营:Sun HotSpot VM.BEA JRockit VM.IB

  • Java对类私有变量的暴力反射技术讲解

    Java对类私有变量的暴力反射 假设有一个类,他有一个私有变量: package com.howlaa.day04; public class ReflectPoint { private int priVar; public ReflectPoint(int priVar){ this.priVar =priVar; } } 如果我们直接采用.get的方式,是不可能看到私有变量的. 我们可以这样: package com.howlaa.day04; import java.lang.refle

  • java request.getHeader("user-agent")获取浏览器信息的方法

    一.User Agent的含义 User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本.CPU 类型.浏览器及版本.浏览器渲染引擎.浏览器语言.浏览器插件等. 一些网站常常通过判断 UA 来给不同的操作系统.不同的浏览器发送不同的页面,因此可能造成某些页面无法在某个浏览器中正常显示,但通过伪装 UA 可以绕过检测. 浏览器的 UA 字串 标准格式为: 浏览器标识 (操作系统标识; 加密等级标识; 浏览器语言) 渲染引擎标识 版本信息 浏

随机推荐