数组与ArrayList

夙愿已清 提交于 2019-12-09 23:50:44

带着问题进入下面的阅读:为什么数组下标从 0 开始而不是 1 呢?

如何实现随机访问?

定义

数组是一种线性表数据结构,用连续的内存空间来存储一组具有相同的数据类型的数据。

  • 线性表

在这里插入图片描述

  • 连续的内存空间和相同的数据类型

正是有了这两个特性:「随机访问」。但是,当我们需要删除或者插入的时候也需要做大量的搬移工作。

说到数据访问, 数组是如何实现根据下标随机访问数组元素 ?如下图:

给数组 a[10] 分配了一块连续内存空间 1000-1039 ,其中内存块的首地址为:base_add=1000

在这里插入图片描述

需要随机访问数组中的某个元素时,它会首先通过下面的寻址公式,计算出该元素存储的内存地址:

a[i]_add = base_add + i * data_type_size

所以,这里加入从 1 开始计数,那么公式应为:

a[i]_add = base_add + (i-1) * data_type_size

如此,每次计算都要减一,所以这是数组从 0 开始的原因之一

低效的插入和删除

因为数组是连续的内存空间,当我们想要在一个数组的中间插入或者删除一个数据,就需要移动部分数据,这很好理解的。

  • 插入

当不需要保证数据有序的时候:

  1. 把要插入位置的元素移动数组末尾
  2. 把元素插入位置

当需要保证数据有序的时候:

  1. 将数组插入位置到数组末尾的所有元素都依次往后移动一位
  2. 把元素插入位置
  • 删除

数组 a[10] 中存储了 8 个元素:a,b,c,d,e,f,g,h。现在,我们要依次删除 a,b,c 三个元素。

为了避免 defgh 这个几个元素多次搬移:

  1. 先将元素标记为删除,并不真正移动
  2. 当数组满了,再统一删除

这就是: JVM 标记清除垃圾回收算法的核心思想

警惕数组越界

Java 中不存在数组越界问题,因为会直接抛出错误;如下代码:

public class TestObject {
    
    public static void main(String[] args) {
       int[] a=new int[3];
       a[0]=1;
       a[1]=2;
       a[2]=3;
       for(int i=0;i<=3;i++){
           System.out.println(a[i]+",");
       }
    }
}

//outPut:
1,
2,
3,
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at testAll.ThinkingInJava.TestObject.main(TestObject.java:18)

容器 VS 数组

如果你是做 Java 业务开发,那么 99.9% 的时间都是直接使用容器(ArrayList)而不是数组;

数组

int[] i={};  //大小为0
int[] i1=new int[5];  //5
int[] i2=new int[]{};  //0
//不能同时指定大小,又初始化数据
//比如:int[] i2=new int[5]{};

Java 中数组本身在定义的时候需要预先指定大小,因为需要分配连续的内存空间。如果我们申请了大小为10的数组,当第11个数据需要存储到数组中时,我们就需要重新分配一块更大的空间,将原来的数据复制过去,然后再将新的数据插入

ArrayList

我们不用关心底层扩容逻辑,每次存储空间不够的时候,他都会自动将空间扩容为 1.5 倍大小。

因为扩容涉及内存申请和数据搬移,所以如果能够事先确定存储的数据大小,最好在创建 ArrayList 的时候就指定数据大小

总结对比:

  1. 在 Java 日常开发中都是直接使用容器,封装了实现细节,并且可以动态扩容
  2. ArrayList 无法存储基本数据类型

参考:
极客时间 - 数据结构与算法之美

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!