你真的理解Java中的ArrayList吗

目录
  • 1. 为什么需要ArrayList?
  • 2. ArrayList底层是如何实现的?
  • 3. 结合源码分析主要成员变量
  • 4. 个人的一点总结

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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java ArrayList集合中的某个对象属性进行排序的实现代码

    开发中有时候需要自己封装分页排序时,List如何对某一属性排序呢,分享一个小实例,大家共勉,希望能对大家有用,请多多指教. 1.Student的Bean如下: public class Student { private int age; private String name; private String weight; public String getWeight() { return weight; } public void setWeight(String weight) { th

  • java的arraylist排序示例(arraylist用法)

    写了一个java数组排序示例,这里分享给大家共同学习 复制代码 代码如下: package com.yonyou.test;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;public class Test { public static void main(String[] args) {  Student zlj = new St

  • JAVA ArrayList详细介绍(示例)

    第1部分 ArrayList介绍ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口.ArrayList 继承了AbstractList,实现了List.它是一个数组队列,提供了相关的添加.删除.修改.遍历等功能.ArrayList 实现了RandmoAccess接口,即提供了随机访问功能.Randmo

  • java 对ArrayList进行分页实例代码

    java 对ArrayList进行分页 概述 系统与系统之间的交互,通常是使用接口的形式.假设B系统提供了一个批量的查询接口,限制每次只能查询50条数据,而我们实际需要查询500条数据,这个时候可以对这500条数据做分批操作,分10次调用B系统的批量接口. 如果B系统的查询接口是使用List作为入参,那么要实现分批调用的话,可以利用ArrayList的subList方法来处理. 代码 sublist方法的定义: List<E> subList(int fromIndex, int toInde

  • Java中ArrayList的removeAll方法详解

    本文介绍的是关于Java中ArrayList的removeAll方法的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍: 在开发过程中,遇到一个情况,就是从所有骑手Id中过滤没有标签的骑手Id(直接查询没有标签的骑手不容易实现), List<Integer> allRiderIdList = new ArrayList(); // 所有的骑手,大致有23W数据 List<Integer> hasAnyTagRiderId = new ArrayList(); // 有标签

  • java ArrayList按照同一属性进行分组

    java ArrayList按照同一属性进行分组 前言: 通常使用SQL查询一批数据的时候,可以利用SQL中的GROUP BY语句对数据进行分组,但是有时候出于对性能的考虑,不会使用GROUP BY,而是先把数据捞出来后,使用代码,在内存中按照某个属性进行分组. 代码 public class SkuVo { private Long skuId; private String productName; private Long brandStoreSn; public SkuVo(Long s

  • Java ArrayList 数组之间相互转换

    做研发的朋友都知道,在项目开发中经常会碰到list与数组类型之间的相互转换,本文通过一个简单的例子给大家讲解具有转换过程. Java代码 package test.test1; import java.util.ArrayList; import java.util.List; public class Test { /** * @param args */ public static void main(String[] args) { List list=new ArrayList(); l

  • Java中Arraylist动态扩容方法详解

    前言 本文主要给大家介绍了关于Java中Arraylist动态扩容的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. ArrayList 概述 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长.ArrayList不是线程安全的,只能用在单线程环境下.实现了Serializable接口,因此它支持序列化,能够通过序列化传输:实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问:实现了Cloneable接口,能被克隆.

  • Java针对ArrayList自定义排序的2种实现方法

    本文实例讲述了Java针对ArrayList自定义排序的2种实现方法.分享给大家供大家参考,具体如下: Java中实现对list的自定义排序主要通过两种方式 1)让需要进行排序的对象的类实现Comparable接口,重写compareTo(T o)方法,在其中定义排序规则,那么就可以直接调用Collections.sort()来排序对象数组 public class Student implements Comparable{ private int id; private int age; p

  • Java中ArrayList类的使用方法

    Java中ArrayList类的用法 1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和IList接口 灵活的设置数组的大小 2.如何使用ArrayList 最简单的例子: ArrayList List = new ArrayList(); for( int i=0;i <10;i++ ) //给数组增加10个Int元素 List.Add(i); //..

随机推荐