你真的理解Java中的ArrayList吗

 更新时间:2021年08月05日 10:34:57   作者:Jack·Kwok  
这篇文章主要给大家介绍了关于Java中ArrayList的相关资料,ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,需要的朋友可以参考下

1. 为什么需要ArrayList?

图1 图2

记得在刚刚学习Java的时候,我们首先是学习了数组,这是我们学到的第一个可以存储多个对象的实例或者基本类型的具体值,数组存储的特点如下:

  1. 只能存储同种类型的数据。
  2. 在定义数组时,必须指定该数组的大小,并且在不改变数组的前提下,不可修改其长度。

以上特性就会导致很多弊端。比如:我们往往不希望数组只能存储一种数据,而是希望存储我们想要存储的数据,最好是在想要存储的时候根据数据的类型指定存储的类型。其次,我们也不想一开始就指定好数据的长度,而是希望这个数组的容量可以随着我的数据的多少的改变而改变。

基于以上的弊端,Java中出现了集合。这是一种新的容器可以用来存储数据,而集合的存储方式有多种,常见的有链式存储(LinkedList)和顺序存储(ArrayList)。

链式存储底层是用一个个节点(Node)链接而成的,每个节点都存储着一个对象值和下一个节点的位置(或上一个节点的位置)。

顺序存储底层是用一个数组存储数据的,对于数组的弊端,顺序存储集合底层使用了ensureCapacity这个方法不断扩容,ensureCapacity这个单词字面翻译是 保证能力。顾名思义,由于底层是一个数组,当我们存入一个对象时,我们需要保证数组是有空余位置的,因此在添加元素的时候,Java源码会先经过这个方法进行判断底层数组是否满了,若满了则会扩容数组(上面提到数组是不能直接扩容的,这里实际上是重新创建了一个更大空间的数组并把元素“搬运”过去)。这样就解决了数组的一个弊端。而对于另一个弊端,Java则是巧妙的运用了泛型。泛型的内容非常繁多,这里结合实例希望大家可以更好的理解。

想象一下现在有一个需求,需要你实现一个的多值加法,但传入的参数的类型是不确定的,可以有Integer,String,Double等等。这时候如果你用的是数组作为参数,那么那你肯定会想,最粗糙的方法是分别写多个加法方法,对应不同的类型,但很明显,代码可读性极差,那如果使用Object数组,然后再根据数据类型,转换为对应的类型再计算?这样也存在弊端!你根本不知道需要转换为什么类型才合适。因此,针对这种情况,使用泛型集合是最合适的,我们只需要在传入参数的时候使用泛型类型,而因为不同类型计算的过程是一致的,因此结果并没有差别,也不会导致报错。

2. ArrayList底层是如何实现的?

简单介绍了ArrayList的用途以及和数组的区别,那么根据上面的讲解,你应该大致了解它的实现原理了吧!

先不看源码,如果你有一些数据结构与算法的基础的话,你应该可以马上得出下面结论:先在ArrayList类定义一个数组,接着定义一个添加,一个删除,一个查询,一个修改方法。实际上是对数组的操作,那么,删除和添加可能需要移动大量的元素,这些都是在源码中实现,但对应到效率也会很低,其次还需要一个扩容数组的方法。

如果你能想到上面这些,恭喜你,你已经掌握的很不错。事实上,ArrayList的源码确实包含以上方法,只不过还需要加上迭代器以及构造方法等。迭代器的出现是为了适应增强for语句(后面会细说),构造方法是为了初始化集合。

3. 结合源码分析主要成员变量

ArrayList继承AbstractList这个抽象类和List接口

List

接口继承Collection接口(实际上集合还有map集合等)

而Collection则是继承了Iterable(可迭代的),Collection中包含了集合中通用的方法,包括增删改查,只不过都未实现。而Iterable则是只有一个forEach方法,提供迭代。

接着我们回到ArrayList类,这是底层维护的数组,实际上对象存储的地方

,

记录集合的长度

返回集合的长度

判断集合是否为空

根据索引获取元素

添加元素

添加元素到指定位置

删除元素

内部类的next方法实现迭代功能(我们平时使用增强for语句的判断条件就是根据判断是否有next值来实现的)

4. 个人的一点总结

Java的设计者很巧妙的设计了Java中的每个功能,很多时候,我们会觉得说我手动实现简单的集合不需要这么复杂的代码呀?甚至有些功能都不需要单独作为一个方法。但这就是Java的魅力啊!

以前刚学代码的我们,把代码全都丢到main方法里面,我们会觉得提取出来是多么复杂,但当我们知道功能是有区别的,我们才知道这样子做的用处。
曾经有个老师这么对我说,他说你知道为什么我们要费尽心思去设计各种类之间的关系,接口,抽象类,泛型等等吗?那时候的我一脸茫然,他对我说,打个比方,你见过卖水果的店里还卖手机的吗?我听完后恍然大悟,对于一个小城镇,确实可能存在一个小店卖着各种杂七杂八的东西,但一个千万人口的大城市,是做不到的,这是格局啊!各种功能,各种设施都应该井井有条,关系明确。面向对象也好,设计模式也好,一切的功能都是为了大型程序做准备,这也是为什么Java一直可以大型应用的后端程序语言之一。

到此这篇关于Java中ArrayList的文章就介绍到这了,更多相关Java中ArrayList内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java使用TimeZone将中国标准时间转成时区值

    java使用TimeZone将中国标准时间转成时区值

    这篇文章主要介绍了java使用TimeZone将中国标准时间转成时区值的相关资料,需要的朋友可以参考下
    2023-11-11
  • springboot集成spring cache缓存示例代码

    springboot集成spring cache缓存示例代码

    本篇文章主要介绍了springboot集成spring cache示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • java中将科学计数法转换普通计数法的简单方法

    java中将科学计数法转换普通计数法的简单方法

    下面小编就为大家带来一篇java中将科学计数法转换普通计数法的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • Java基础之FastJson详解

    Java基础之FastJson详解

    今天给大家复习Java基础FastJson,文中有非常详细的代码示例,对正在学习java的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • Maven jar包下载失败问题的处理方法

    Maven jar包下载失败问题的处理方法

    很多同学在Maven里下载一些依赖的时候,即下载jar包的时候总是会出现一些问题,本文将就这个问题给大家详细的讲解一下,需要的朋友可以参考下
    2023-06-06
  • Tomcat内存溢出分析及解决方法

    Tomcat内存溢出分析及解决方法

    堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的,本文将详细介绍Tomcat内存溢出,需要了解更多的朋友可以参考下
    2012-11-11
  • java中FileOutputStream中文乱码问题解决办法

    java中FileOutputStream中文乱码问题解决办法

    这篇文章主要介绍了java中FileOutputStream中文乱码问题解决办法的相关资料,需要的朋友可以参考下
    2017-04-04
  • Lucene单值编码压缩算法源码解析

    Lucene单值编码压缩算法源码解析

    这篇文章主要为大家介绍了Lucene单值编码压缩算法源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • Mybatis条件if test如何使用枚举值

    Mybatis条件if test如何使用枚举值

    这篇文章主要介绍了Mybatis条件if test如何使用枚举值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • 轻松搞定SpringBoot JPA使用配置过程详解

    轻松搞定SpringBoot JPA使用配置过程详解

    Spring Boot是由Pivotal团队提供的全新框架,该框架使用了特定的方式来进行配置,它默认配置了很多框架的使用方式,就像 Maven整合了所有的Jar包,Spring Boot 整合了所有的框架
    2021-06-06

最新评论