深入理解数组:从概念到实践

1.写在前面

我们在了解/学习一个新技能之前,都会先了解这个技能的概念。搞清楚是用来干嘛的,能解决什么问题、这样的话,方便后面正确的打开,磨刀不误砍柴工。
同时,数组不仅仅是某一编程语言中的数据类型,它还是一种最基础的数据结构。

2.数组的概念(维基百科):

数组数据结构(array data structure),简称数组(Array),是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。利用元素的索引(index)可以计算出该元素对应的存储地址。(这个地方思考一个问题,数组为什么可以随机访问?)

大白话解释一下:
数组是一种数据结构,只能存储同一类型值。意思就是,你创建了一个String类型的数组,那么你这个数组只能存储String 类型的数据,放其他的要报错。

2.1怎么访问数组中的数据呢?

可以通过下标访问数组中的每一个值,比如有这样一个数组:
int [] intArray = {25,14,5,3,6};我们画个图
在这里插入图片描述
看这个图,intArray[2] 访问的就是 intArray 数组中 5 这个元素,下标是从0开始的。
通过下标,我们能访问数组中每一个元素。

3.数组的特点:

  1. 定长:数组的长度一旦确定就不能修改
  2. 创建数组时会开辟一块连续的内存来存储
  3. 存取元素的速度快,可以通过索引,快速定位到任意一个元素
    关于通过索引快速定位到一个元素的原理,我在一文看懂ArrayList的自动扩容这篇文章中有说明。感兴趣的话,可以看看。
3.1定长怎么理解呢?

就是说:你创建数组的时候,若初始化数组的长度为5,那么你只能往数组中插入5个元素,你往里面插入第六个元素的时候,会提示你溢出的错误。5个元素,那下标就是[0,4] 若你试图访问a[5] 这个元素,程序会引发“array index out of bounds” 异常而终止执行。

4.数组的声明与初始化

4.1 声明
// 声明语法1:数据类型[] 数组名
int[] arr;

// 声明语法2:数据类型[] 数组名
int arr[];

这两种风格你喜欢哪种呢?个人比较喜欢第一种风格,因为它将类型int[] (整型组数) 与变量名arr 分开了,看上去更加清晰。

4.2初始化
4.2.1静态初始化:
// 方式一:数据类型[] 数组名 = {元素1,元素2,元素3,...}
int[] arr = {1,2,3,4};

// 方式二:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
int[] arr = new int[]{1,2,3,4};
4.2.2动态初始化:
//数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度];

int[] arr = new int[5]
4.3数组元素的访问
4.3.1对于数组来说,我们通过元素的索引访问,那什么是索引呢?

索引:前面我们有提到创建数组,内存会分配一块连续的空间来存储,第一个元素所在内存的地址称为基地址,那么第一个元素相对于基地址来说,偏移量为0,所以索引是从0开始,那么第二个地址与基地址之间就偏移了1. 因此,索引的范围为:[0,数组的长度-1] .

利用元素的索引(index)可以计算出该元素对应的存储地址,

通过 array.length 可以获得数组中元素的个数。

4.3.2数组的遍历
public static void main(String[] args) {
  	int[] arr = new int[]{1,2,3,4,5};
  	//打印数组的属性,输出结果是5
  	System.out.println("数组的长度:" + arr.length);
    
    //遍历输出数组中的元素
    System.out.println("数组的元素有:");
    for(int i=0; i<arr.length; i++){
        System.out.println(arr[i]);
    }
}
4.3.3数组元素的默认值

当我们动态初始化数组时:

//数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度];

int[] arr = new int[5]

此时只确定了数组的长度,那么数组的元素是什么值呢?

数组元素类型元素默认值
byte0
short0
int0
Long0L
float0.0F
double0.0
char0或写为:‘\u0000’(表现为空)
引用类型null
4.4数组的拷贝

在Java中,可以将一个数组变量拷贝给另一个数组变量,这个时候,两个变量引用的是同一个数组。

int[] firstArray = {1,2,3,45};
int[] secondArray = firstArray ;

这个时候,secondArray 引用的就是 firstArray 的地址,这两个数组是一样的。
在这里插入图片描述
那如果 希望将一个数组的所有值拷贝到一个新的数组中去呢?

4.4.1全新拷贝

Arrays类的copyOf 方法:

int[] copiedArray=Arrays.copyOf(firstArray ,firstArray .length);

第一个参数是要拷贝的数组。第二个参数是数组的长度
Arrays.copyOf 这个方法通常用来增加数组的大小。比如

int[] copiedArray=Arrays.copyOf(firstArray ,2 * firstArray .length);

拷贝firstArray 数组,并且将数组扩大为firstArray 数组大小的两倍.
那么问题来了,多余的元素的默认值是什么呢?
int 类型的就是0, 布尔类型的就是false.
相反: 如果长度小于原始数组的长度呢?
这种请跨的话,只拷贝最前面的数据元素。
比如元素数组的长度为10,拷贝时你传的参数是5,那就只拷贝原始数组的前5个元素。

4.5数组的排序

若对数值型数组进行排序,则使用Arrays 类中的sort 方法。

int[] firstArray = {9,58,3,915};
Arrays.sort(firstArray);

Arrays.sort() 使用了优化的快速排序方法,快排算法对于大多数数据集合来说都是效率比较高的。

5.数据的下标为什么从0开始?

我们之前在概念中提到:利用元素的索引(index)可以计算出该元素对应的存储地址。时,让大家思考一个问题,为什么数据可以随机访问呢?主要就是以下两点:

  1. 数组是一种线性结构
  2. 连续的内存空间和相同的数据结构

计算机会给数组分配连续的内存空间,这块内存有一个首地址,我们访问数组的某个元素的时候,会通过一个寻址公式

来计算存储的地址,公式:arr[i]_address = base_address + i * data_type_size(arr[i] 首地址 = 数组内存块首地址 + 数据类型大小 * i ,其中i为偏移量。)

baseaddress:内存块的首地址。datatype_size:数组中每个元素的大小,如:每个元素大小是4个字节,我们都知道,是通过元素的地址来访问内存中的数据,那么,我们就可以根据首地址 + 偏移量 来随机访问每个元素啦,数组中的下标就是偏移量第一个元素就是首地址,偏移量为0,所以数据下标从0开始, ,根据下标和首地址,数据就可以随机访问数组中的元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

书语时

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值