JDK1.8--ArrayList

java中集合是重要的部分之一,在实际工作过程也被高频率使用,这里大概记录一下1.8中的ArrayList,主要分析一下几个常用的方法,扩容机制,以及多线程下引起的线程安全问题,纯属个人拙见,不足之处还请评论支出,共同学习进步!

1.对于集合整体架构如下图所示:

 通过源码我们可以看到ArrayLis的底层数据结构是数组,这也赋予了它检索效率高的优势,但是由于数组的局限性,达到一定容量时需要扩容,为了减少扩容带来性能降低,我们在使用ArrayList初始化时可以根据使用场景预估其长度而定一个初始容量值,这样可以减少频繁扩容而带来不必要的开销。

2.常用方法

构造方法

通过注释我们可以看出来三个构造方法适用于不同的场景,

/**
 * Constructs an empty list with the specified initial capacity.
 * 初始容量值的构造方法
 */
public ArrayList(int initialCapacity);

/**
 * Constructs an empty list with an initial capacity of ten.
 * 无参构造方法,初始容量为10
 */
public ArrayList();

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 * 构建一个包含具体集合元素的构造方法,它们的顺序依次通过集合的迭代器返回
 */
public ArrayList(Collection<? extends E> c);

添加元素方法

  • 一个参数的add方法

/**
 * Appends the specified element to the end of this list.
 * 在list的末尾增加元素e
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

我们先来说说ArrayList的两个重要参数,如注释

/**
 * Shared empty array instance used for empty instances.
 * 用于空实例的空数组实例
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * 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.
 * 用于默认大小空实例的空数组实例,我们将此与EMPTY_ELEMENTDATA区别开来,以了解添加第一个元素时需要扩容多少。
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

我们继续跟进add方法

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

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) {
    // 操作数记录变量,Java快速报错机制后续分析
    modCount++;

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

calculateCapacity这个方法就利用了如上的两个参数,如果是使用默认无参构造方法也就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组对象时,增加第一个元素E e返回的是默认的容量长度DEFAULT_CAPACITY,在进入ensureExplicitCapacity方法后,经过if判断后进行扩容,执行grow方法,我们继续看grow方法

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 * 增加容量以确保它至少可以容纳最小容量参数指定的元素数量。简而言之就是扩容
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // 右移1位操作,等效于oldCapacity/2,但是位移是底层操作更高效
    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);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

对于扩容有几种情况:

  • 如果使用默认构造方法,增加第一个元素时minCapacity = 10,经过grow方法后数组elementData从0扩容到10,后续再增加元素扩容时则是1.5倍的扩容
  • 如果使用初始值构造方法,但是初始容量为0时,增加第一个元素minCapacity=1,经过grow方法后数组elementData从,0扩容到1,在第5次添加数据进行扩容的时候才是按照当前容量的1.5倍进行扩容
  • 当扩容量(newCapacity)大于ArrayList数组定义的最大值后会调用hugeCapacity来进行判断。如果minCapacity已经大于Integer的最大值(溢出为负数)那么抛出OutOfMemoryError异常

至此ArrayList扩容机制分析完毕,扩容完成后,添加新元素E e。

在ensureExplicitCapacity方法中有个一个增量modCount,这里是利用了java的快速报错机制,也算是一种保护机制,能够防止多个进程同时修改同一个容器的内容。如果迭代遍历比如使用迭代器Iterator(ListIterator)或者forEach,会将modCount变量值传给exceptedModCount,并且会检查modCount与exceptedModCount是否相等,如果此时对同一个容器执行新增删除或者修改操作,modCount会改变,二者不相等则会抛出ConcurrentModificationException异常。但是如果使用Iterator的remove方法则不会发生此异常。举例如下:

 

 剩下的三个添加元素的方法在此不再赘述。

此篇主要内容到此结束,有不足之处还请大家指正,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在JDK 1.8中,API文档是用英文编写的,但是我可以为你提供一些英文和中文对照的示例。 1. Object类 (Object class) - equals()方法: 判断两个对象是否相等。 - toString()方法: 返回对象的字符串表示。 - hashCode()方法: 返回对象的哈希码值。 2. String类 (String class) - length()方法: 返回字符串的长度。 - charAt()方法: 返回指定位置的字符。 - substring()方法: 返回子串。 3. ArrayList类 (ArrayList class) - add()方法: 将元素添加到ArrayList。 - get()方法: 获取指定位置的元素。 - remove()方法: 删除指定位置的元素。 4. HashMap类 (HashMap class) - put()方法: 将键值对添加到HashMap。 - get()方法: 根据键获取对应的值。 - remove()方法: 根据键删除键值对。 5. DateTimeFormatter类 - parse()方法: 将字符串解析为日期时间对象。 - format()方法: 将日期时间对象格式化为字符串。 请注意,这只是一小部分JDK 1.8 API中的方法示例,整个API文档提供了更多详细的说明和示例。您可以参考官方的JDK 1.8 API文档以获取更全面的信息。 ### 回答2: 1. java.lang 包下的常用类: - Object:对象类 - Class:类类 - String:字符串类 - StringBuilder:字符串构建器类 - StringBuffer:字符串缓冲类 - System:系统类,提供与系统相关的方法和属性 - Math:数学类,提供数学相关的方法和常量 - Boolean:布尔类 - Byte:字节类 - Character:字符类 - Short:短整数类 - Integer:整数类 - Long:长整数类 - Float:单精度浮点数类 - Double:双精度浮点数类 - Enum:枚举类 - Throwable:可抛出对象类,是所有错误和异常的基类 2. java.util 包下的常用类: - ArrayList:动态数组类 - LinkedList:链表类 - HashMap:哈希映射类 - LinkedHashMap:有序哈希映射类 - TreeSet:树集类 - TreeMap:树映射类 - HashSet:哈希集合类 - LinkedHashSet:有序哈希集合类 - Queue:队列接口 - PriorityQueue:优先队列类 - Stack:栈类 - Iterator:迭代器接口 - ListIterator:列表迭代器接口 - Comparator:比较器接口 - Calendar:日历类 - Date:日期类 - Timer:定时器类 3. java.io 包下的常用类: - File:文件类 - InputStream:输入流接口 - OutputStream:输出流接口 - Reader:字符输入流接口 - Writer:字符输出流接口 - BufferedReader:缓冲字符输入流类 - BufferedWriter:缓冲字符输出流类 - FileReader:文件字符输入流类 - FileWriter:文件字符输出流类 - FileInputStream:文件字节输入流类 - FileOutputStream:文件字节输出流类 - ObjectInputStream:对象输入流类 - ObjectOutputStream:对象输出流类 - PrintWriter:打印输出流类 - RandomAccessFile:随机访问文件类 - ByteArrayInputStream:字节数组输入流类 - ByteArrayOutputStream:字节数组输出流类 - CharArrayReader:字符数组输入流类 - CharArrayWriter:字符数组输出流类 这些只是jdk1.8 API中的一部分常用类和接口,还有很多其他类和接口不一一列举。 ### 回答3: JDK 1.8中的API是指Java开发工具包1.8版本中提供的所有类、接口和方法,它们用于开发Java应用程序。下面是一些常用API的中英文对照: 1. java.lang包: - Object: 对象 - String: 字符串 - Integer: 整型 - Double: 双精度浮点型 - Math: 数学计算 2. java.util包: - ArrayList: 数组列表 - LinkedList: 链表 - HashMap: 哈希表 - TreeSet: 树集合 - PriorityQueue: 优先队列 3. java.io包: - File: 文件 - InputStream: 输入流 - OutputStream: 输出流 - BufferedReader: 缓冲读取器 - BufferedWriter: 缓冲写入器 4. java.awt包: - Frame: 框架 - Button: 按钮 - Label: 标签 - TextField: 文本框 - Checkbox: 复选框 5. java.net包: - Socket: 套接字 - ServerSocket: 服务器套接字 - URL: 统一资源定位符 - HttpURLConnection: HTTP连接 这只是JDK 1.8 API中一小部分常用类和接口的中英文对照,实际上API包含了更多的类和接口,用于满足不同的编程需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值