Java集合类--ArrayList

本文详细介绍了Java中ArrayList的工作原理,包括创建、添加、删除元素的方法,以及遍历和扩容策略等关键操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.cnblogs.com/huangfox/archive/2010/10/09/1846758.html 


Java集合类 

一、 概述 

集合类是java中常用的工具,使用频率最多的是Collection和Map两个接口的实现类,Collection存放多个单对象,而Map存放多个Key-value形式的键值对。

Collection又分成两大接口:List和Set,其最大的区别就是List容许存放重复的对象,而Set不行。常见的实现类参见下图:

图——Collection常见的实现类

在集合类的应用当中,我们需要注意以下几点:

  • Collection的创建;
  • Collection添加对象;
  • Collection删除对象;
  • 获取Collection当中单个对象;
  • 遍历Collection中的对象;
  • 判断对象是否存在于Collection中;
  • Collection中对象的排序;

 

 

 

二、 ArrayList
   

2.1      创建ArrayList()

public ArrayList(int initialCapacity) {

    super();

       if (initialCapacity < 0)

           throw new IllegalArgumentException("Illegal Capacity: "+

                                              initialCapacity);

    this.elementData = new Object[initialCapacity];

    }

super()为一个空方法,因此在创建ArrayList的最重要的语句是:

this.elementData = new Object[initialCapacity];

他实例化了一个Object数组,并且将该数组赋给了当前实例的elementData属性,此数组的大小由initialCapacity指定。因此可知ArrayList是由对象数组存放数据的。

2.2      添加对象:add(E)

添加一个对象即将该对象插入到elementData数组当中,但是当数据满时,需要对其进行扩容。

public boolean add(E e) {

    ensureCapacity(size + 1);  // Increments modCount!!

    elementData[size++] = e;

    return true;

    }

public void ensureCapacity(int minCapacity) {

    modCount++;

    int oldCapacity = elementData.length;

    if (minCapacity > oldCapacity) {

        Object oldData[] = elementData;

        int newCapacity = (oldCapacity * 3)/2 + 1;

        if (newCapacity < minCapacity)

       newCapacity= minCapacity;

           // minCapacity is usually close to size, so this is awin:

           elementData = Arrays.copyOf(elementData, newCapacity);

    }

    }

当add(E)时,首先将当前ArrayList中的对象数量加1,赋值给变量minCapacity,然后将其与Object数组的大小进行比较,如果minCapacity大,先将Object数组赋值给一个新的数组对象(oldData),然后生成一个新的数组容量值。新数组容量值为当前容量的1.5倍再加1。最后调用Arrays.copyOf来生成新的数组对象。

如果想修改ArrayList的扩容策略,可继承ArrayList,并覆盖ensureCapacity方法。

2.3      添加对象:add(int,E)

将对象添加的到指定位置,那么就必须将该位置以后的所有数据向后移动一个位置。在这个过程中需要考虑数组容量的问题。

public void add(int index, E element) {

    if (index > size || index < 0)

        throw new IndexOutOfBoundsException(

       "Index: "+index+",Size: "+size);

 

    ensureCapacity(size+1);  // Increments modCount!!

    System.arraycopy(elementData,index, elementData, index + 1,

            size - index);

    elementData[index] = element;

    size++;

    }

首先将指定位置后的数据移动一个位置:

System.arraycopy(elementData, index, elementData, index + 1,

            size - index);

然后见预添加的对象插入到指定位置:

elementData[index] = element;

知识点扩充 

arraycopy

publicstatic void arraycopy(Object src, int srcPos, Object dest, int destPos,int length)

从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。从 src 引用的源数组到 dest 引用的目标数组,数组组件的一个子序列被复制下来。被复制的组件的编号等于 length 参数。源数组中位置在 srcPos 到 srcPos+length-1 之间的组件被分别复制到目标数组中的 destPos 到 destPos+length-1 位置。

如果参数 src 和 dest 引用相同的数组对象,则复制的执行过程就好像首先将 srcPos 到 srcPos+length-1 位置的组件复制到一个带有 length 组件的临时数组,然后再将此临时数组的内容复制到目标数组的 destPos 到 destPos+length-1 位置一样。

 

2.4      删除对象:remove(E)

public boolean remove(Object o) {

    if (o == 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;

    }

重点关注:

fastRemove(index);

private void fastRemove(int index) {

       modCount++;

       int numMoved = size - index - 1;

       if (numMoved > 0)

           System.arraycopy(elementData,index+1, elementData, index,

                            numMoved);

        elementData[--size] = null; // Let gc do its work

    }

获得预删除对象的位置(index),传入fastRemove,将index后所有数据向前移动一个单位,并且将最后一个数据设置为null,然gc对其进行回收。

Remove(E)比较耗时的步骤是:遍历数组与目标数据进行比较。

2.5      删除数据:remove(int)

public E remove(int index) {

    RangeCheck(index);

 

    modCount++;

    EoldValue = (E) elementData[index];

 

    int numMoved = size - index - 1;

    if (numMoved > 0)

        System.arraycopy(elementData, index+1, elementData, index,

                numMoved);

    elementData[--size] = null; // Letgc do its work

 

    return oldValue;

    }

虽然remove(int)多了一步

RangeCheck(index);范围检测 

但是不用对数据进行比较,因此remove(int)的效率比remove(E)的效率要高。

2.6      遍历对象:iterator()

关于iterator实例:

public Iterator<E> iterator(){

    return new Itr();

    }

每次调用iterator方法返回一个Itr实例,该实例包含属性

Cursor,

Cursor起到光标的作用,在hasNext中与当前数据的长度进行比较,如果相等则说明遍历完成,返回false。

public boolean hasNext() {

           return cursor != size();

    }

Iterator实例还包含属性

expectedModCount

expecteModeCount描述了在创建iterator时ArrayList实例的状态,即获取那时modCount的值。

public E next() {

           checkForComodification();

        try {

       Enext = get(cursor);

       lastRet = cursor++;

       return next;

        } catch (IndexOutOfBoundsException e) {

       checkForComodification();

       throw newNoSuchElementException();

        }

    }

对ArrayList实例中对象数组的大小产生影响的动作将会影响实例的modCount属性,在next方法中,需要iterator持有的expecteModeCount与当前的modCount进行比较,若不相同则说明在iterator遍历的过程中ArrayList实例发生了变化(对象数组长度发生变化)。该功能由checkForComodfication方法执行:

final void checkForComodification() {

        if (modCount != expectedModCount)

       throw newConcurrentModificationException();

    }

    }

因此在使用iterator对ArrayList实例进行遍历的过程中,不能使用add、remove等方法。

2.7      判断存在或获取位置 

Contains(E)、indexOf、lastIndexOf无非都是对对象数组的遍历和数据之间的比较,不做过多说明。

2.8      注意点 

  • ArrayList是无容量限制的。
  • ArrayList在删除数据时并不会减小数组的容量,如果想要减少数组容量可以使用trimToSize方法。
  • 在查找数据时,遍历数组,对非null的数据使用的是equal进行比较。
  • ArrayList是非线程安全的。
基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值