`

深入java集合类系列:ArrayList

阅读更多

   ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小,下面将从ArrayList的属性及相关方法进行概述

属性

private transient Object[] elementData;

 为实际数据的存储对象,可以看出ArrayList实际存储数据对象为对象数组,所以ArrayList实际为对对象数组操作的封装,从这里我们也可以看出ArrayList没有容量限制。 

 private int size;

 当前对象数组中已经存在元素个数size小于等对象数组的大小,

创建

ArrayList API提供了三种构造方法,常用的两种如下

    public ArrayList() {
	//调用ArrayList(int initialCapacity)
	this(10);
    }
    public ArrayList(int initialCapacity) {
	super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
	//创建存储数据对象
	this.elementData = new Object[initialCapacity];
    }

 对于默认的new ArrayList()来说,可以分析得到创建默认大小的object数组,数组的初始化大小为10,默认创建时size未赋值,因是类变量size将初始为0;

增加元素

   public boolean add(E e) {
	//校验数组容量
	ensureCapacity(size + 1);  // Increments modCount!!
	//将数据对象插入到数组的size末端
	elementData[size++] = e;
	return true;
    }
	//插入指定位置的元素
	public void add(int index, E element) {
	//索引>size或索引小于0直接抛出异常
	if (index > size || index < 0)
	    throw new IndexOutOfBoundsException(
		"Index: "+index+", Size: "+size);
	ensureCapacity(size+1);  // Increments modCount!!
	//将index后面的数据后移一位
	System.arraycopy(elementData, index, elementData, index + 1,
			 size - index);
	//将数据插入到指定index位置
	elementData[index] = element;
	//size加一
	size++;
    }
	public void ensureCapacity(int minCapacity) {
	modCount++;
	//原有数组容量大小
	int oldCapacity = elementData.length;
	//插入的索引位置大于数组容量,增大数组容量
	if (minCapacity > oldCapacity) {
	    Object oldData[] = elementData;
		//数组容量增大,按照原数组容量大小0.5增加
	    int newCapacity = (oldCapacity * 3)/2 + 1;
		//增大的容量如果还是小于插入的索引位置,将索引直接赋值给新的数组容量
		if (newCapacity < minCapacity)
			newCapacity = minCapacity;
		//将数组按照新的数组容量进行扩容
        elementData = Arrays.copyOf(elementData, newCapacity);
	}
    }

 增加是先校验底层的对象数组是否能再添加元素,如果没法添加,先将对象数组进行扩容【要进行一次数组拷贝】,扩容因子为0.5。再进行插入。如果能添加元素,直接将数据插入到size对应的索引位置。如果插入到指定位置将会涉及到数组元素的后移【进行一次数组拷贝】,相关请看add(int index, E element)注解。同时我们也可以发现对于NULL值和重复值也未进行处理。

读取元素

    public E get(int index) {
	RangeCheck(index);//校验index大小
	return (E) elementData[index];//获取index位置的数据
    }
    private void RangeCheck(int index) {
	if (index >= size)
	    throw new IndexOutOfBoundsException(
		"Index: "+index+", Size: "+size);
    }

 读取最简单就是从对象数组中将对应索引位置的数据读取出来。读取的索引小于size。

删除

    public E remove(int index) {
	RangeCheck(index);//检查index大小
	modCount++;
	E oldValue = (E) elementData[index];//标记删除位置的值
	int numMoved = size - index - 1;//计算删除索引到size剩入数据
	if (numMoved > 0)//如果剩入数据大于0,则将index后的数据进行前移。
	    System.arraycopy(elementData, index+1, elementData, index,
			     numMoved);
	elementData[--size] = null; //将size大小-1,并将elementData的原来索引位置为size-1的数据清空。
	return oldValue;
    }

 删除涉及到数组的前移,前移的数据范围为删除索引的值+1到size-1的元素。注意我们发现删除并未和写入时一样进行对象数组的大小的自动收缩【即存储容量未发生变化】。

按照元素值进行删除

   public boolean remove(Object o) {
		if (o == null) {
			//遍历数组,发现第一个null值所在地
			for (int index = 0; index < size; index++)
			if (elementData[index] == null) {
				fastRemove(index);
				return true;
			}
		} else {
			//遍历数组,发现第一个元素值所在地
			for (int index = 0; index < size; index++)
				if (o.equals(elementData[index])) {
					//进行删除
					fastRemove(index);
					return true;
				}
		}
		return false;
    }

	 private void fastRemove(int index) {
        modCount++;
		//计算要前移动的数据个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
			//进行数组拷贝将index后数据前移一位
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
		//size-1并将size-1索引位置的元素清空,
        elementData[--size] = null; // Let gc do its work
    }

 按照元素值进行删除,会遍历数组对象,遍历元素个数为删除元素的索引index+1,且只会删除该元素值出现第一个。并且在删除是,对象数组会进行拷贝,拷贝元素个数为size-index-1。

压缩对象数组存储容量

    public void trimToSize() {
	modCount++;
	int oldCapacity = elementData.length;
	//当前数组的大小小于当前数组存储大小进行压缩
	if (size < oldCapacity) {
            elementData = Arrays.copyOf(elementData, size);
	}
    }

  压缩的时候是以size为标准,将对象数组的大小压缩为size一样大小。

清空

    public void clear() {
	modCount++;
	// 将数组中数据清空
	for (int i = 0; i < size; i++)
	    elementData[i] = null;
	//将size大小设置为0
	size = 0;
    }

清空主要进行两件事情:(1):将相关的数据元素设置为NULL值。(2):将size设置为0

其他的不做介绍了,ArrayList主要是针对对象数组的操作,主要围绕size展开。

总结:

(1):ArrayList的实际存储对象为一个数组对象。没有容量大小,可以无限增加【扩展因子为0.5】,只受JVM内存大小限制。

(2):ArrayList中可以包含重复的元素,并可以存储NULL值。

(3):ArrayList的所有方法都是非线程安全的。

(4):ArrayList的索引访问和元素更新方面有着非常优秀的性能,因为不需要花费精力做范围检查,所以从ArrayList的末端添加元素,删除元素也有着非常优秀的性能,除非ArrayList的存储容量不足而需要扩展内部数组的长度【扩展的时候需要数组拷贝】。插入和删除数据需要一个数组的拷贝,需要拷贝的元素数量是ArrayList的元素长度(size-1)减去索引号,对插入来讲,插入元素到ArrayList的第一个元素位置的性能最差,插入到最后一个位子的性能最好,数组拷贝所需的时间会根据元素的数量增加而显著增加。

(5):ArrayList查找指定位置的数据时间为O(1),插入到指定位置的数据时间为O(size-index-1)。

(6):ArrayList插入大量的元素,提前指定ArrayList的大小,防止在插入过程ArrayList进行扩容。

(7):ArrayList按照元素值进行删除时,会遍历数组对象,并且会进行数组拷贝,时间为O(index+1)+O(size-index-1),可以计算总共花费O(size),遍历的对象+拷贝的对对象就等于元素个数。

 

(8):ArrayList删除时,不会调整原有的数组存储容量的大小即在数组存储容量扩容的后删除所用扩容数据后也不会调整整个数组容量大小,手工调用trimToSize进行调整。

分享到:
评论

相关推荐

    深入Java集合学习系列:ArrayList的实现原理

    《深入Java集合学习系列:ArrayList的实现原理》 在Java编程中,ArrayList是集合框架中一个重要的类,属于List接口的实现,它提供了动态数组的功能,允许我们在集合中存储、添加、删除元素,并且可以按索引访问。这...

    深入Java集合学习系列(三):ArrayList实现原理

    Java集合框架中,ArrayList是一种常见的集合实现类,用于存储和操作对象集合。ArrayList基于动态数组的数据结构,因此它能够提供自动扩容的功能,同时也能够快速地进行随机访问。本篇文档将深入探讨ArrayList的内部...

    深入Java集合学习系列

    在"深入Java集合学习系列(二):ArrayList实现原理_尚硅谷_张晓飞.pdf"中,你可以了解到ArrayList的内部结构、扩容机制以及其在不同操作下的性能特点。 其次,HashMap是Java中处理键值对的数据结构,它实现了Map接口...

    【Java面试+Java学习指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    ava基础 基础知识 面向对象基础 Java基本数据类型 string和包装类 final关键字特性 Java类和包 抽象类和接口 代码块和代码执行顺序 Java自动拆箱装箱里隐藏的秘密 ...Java集合详解8:Java集合类细节精讲 JavaWeb

    jdk源码阅读一:ArrayList

    ArrayList作为Java集合框架中的重要组成部分,被广泛应用于各种应用场景。它的主要特点包括: - **基于数组实现**:ArrayList采用数组作为其底层数据结构,这使得访问特定位置的元素非常高效,时间复杂度为O(1)。 -...

    源码解析jdk7.0集合:ArrayList的底层实现原理.pdf

    了解其内部实现原理有助于开发者更好地使用这个集合类,特别是对于性能要求较高的场景,合理预估集合大小或调用扩容方法可以优化性能。此外,了解 ArrayList 的源码还有助于深入理解 Java 集合框架的设计哲学及面向...

    Java集合框架全景:深入理解主要接口和类

    本文将深入探讨Java集合框架中的主要接口与类,帮助读者更好地理解和应用这些工具。 #### 集合框架概述 Java集合框架主要包括四种类型的集合:List、Set、Queue和Map。每种集合都有其独特的特性和应用场景。 - **...

    java集合PDF汇总

    "深入Java集合学习系列(三):ArrayList实现原理_尚硅谷_张晓飞.pdf"可能是重复的,但再次强调ArrayList的实现原理:ArrayList的线程安全性较差,如果在并发环境下操作,需要配合synchronized关键字或者使用并发集合...

    Android:ArrayList学习实例

    在Android开发中,ArrayList是一个非常基础且常用的集合类,它继承自Java的AbstractList,并实现了List接口。ArrayList主要用于存储和管理有序的元素序列,它的核心特点是动态扩容,可以在运行时根据需要自动增加...

    Java集合类详解总结

    ### Java集合类详解总结 在Java编程中,集合框架(Collection Framework)是处理一组对象的强大工具,它提供了标准的数据结构来存储和操作这些对象。Java集合框架主要包括`Collection`、`Set`、`List`、`Queue`、`...

    JAVA提高第十篇 ArrayList深入分析

    ArrayList是Java集合框架中常用的类,它继承自AbstractList,并实现了List接口,提供了一种基于动态数组的数据存储方式。ArrayList的主要优点在于它提供了快速的随机访问,但由于它是基于数组实现的,所以在插入和...

    Java集合排序及java集合类详解

    在本篇中,我们将深入探讨Java集合的排序机制以及集合类的详细使用。 首先,我们来了解一下Java集合的基本分类。Java集合主要分为两大类:List(列表)和Set(集)。List是一个有序的集合,允许元素重复,并且可以...

    Java集合详解,详细讲解java的集合类

    本文将深入讲解Java集合类,特别是Collection接口和其下的List、Set,以及Map接口中的几个重要实现类。 首先,我们来看Collection接口。Collection是最基本的集合接口,它代表一组Object,即它的元素。Collection...

    Java集合类矩阵图

    Java集合类矩阵图是Java编程中非常重要的一个概念,它主要涵盖了Java集合框架中的各种接口、类以及它们之间的关系。这个矩阵图可以帮助开发者更清晰地理解Java集合框架的层次结构和实现方式。在这个矩阵图中,你可以...

    Java 集合类 简单Demo

    本示例主要探讨的是Java集合类的简单使用,通过一个名为`CollectionsTest.java`的文件进行演示。这篇博客文章可能详细解释了如何创建、操作和理解Java集合类的基本概念。 首先,Java集合框架主要包括接口和实现这些...

    Java员工管理系统,ArrayList存储

    这个“Java员工管理系统,ArrayList存储”的项目是一个很好的实践案例,可以帮助开发者深入理解Java集合框架,特别是ArrayList的使用,同时也能提升面向对象编程和系统设计的能力。通过完成这个项目,开发者可以学习...

    深入探索Java集合框架:解密复杂的面试题和精准解析

    本文将深入探讨Java集合框架的核心概念,包括List、Set、Map等接口,以及ArrayList、LinkedList、HashSet、HashMap等实现类,帮助你理解和解决面试中的相关问题。 1. **List和Set的区别及应用场景** - **List** 是...

    java集合类的代码

    下面我们将深入探讨Java集合类的一些关键知识点: 1. **ArrayList和LinkedList**: - `ArrayList`:基于动态数组实现的集合,适合频繁的随机访问,但插入和删除元素时效率较低,因为需要移动大量元素。 - `...

    java 集合类讲解

    在本讲解中,我们将深入探讨Java集合类的基本原理、特性以及如何在实际开发中灵活运用。 首先,我们要理解Java集合类的核心接口。`Collection`是最基础的接口,所有的集合都继承自它。`List`接口扩展了`Collection`...

Global site tag (gtag.js) - Google Analytics