数组,无论在哪种编程语言当中都是最基础,最广泛使用的一种线性表数据结构,这篇文章将从多个角度来从浅入深的讲述数组。
本文讲述了数组的概念,定义,初始化方法以及如何遍历数组,如何赋值,关于数组越界的问题以及数组在JVM内存中的知识。
一、数组的基本知识
1.1、数组的概念
- 数组指的是一种容器,可以用来存储 同种数据类型 的多个值。
- 数组在存储数据的时候需要结合 隐式转换 来考虑。
- 数组中若有 整形 和 浮点型 数据,则Boolean类型的数据都存不进去。
- 数组一旦创建,长度是固定的,无法动态改变。
隐式转换
简单数据类型(不包括boolean):
在Java中整型、实型(常量)、字符型被视为简单数据类型,由低级到高级分别为:
(byte,short,char) -> int -> long -> float -> double隐式转换:
在java中这些简单数据类型从低级转换到高级就是隐式转换,例如如果是double类型的数组,则可以存储所有的简单数据类型,这些比double低级的数据会隐式的转换为double类型存储。
但是如果是int类型的数组,则 long、float、double都不能存入进去。
1.2、数组的定义
1.3、数组的初始化
数组的初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
- 静态初始化:
- 完整格式:数据类型[ ] 数组名 = new 数据类型[ ]{元素1,元素2,元素3...}
范例:int [] array = new int[ ]{1,2,3 } - 简化格式:数据类型[ ] 数组名 = {元素1,元素2,元素3}
范例:int[ ] array = {11,22,33 };
- 完整格式:数据类型[ ] 数组名 = new 数据类型[ ]{元素1,元素2,元素3...}
- 动态初始化:初始化时只指定数组长度,由系统为数组分配初始值。
- 格式:数据类型[ ] 数组名=new 数据类型[数组长度];
- 范例:dataType[ ] arrayRefVar = new dataType[arraySize];
- 区别:
- 动态初始化:手动指定数组长度,由系统给出默认初始化值,只明确元素个数;
使用场景:不明确具体数据,推荐使用动态初始化; - 静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度;
使用场景:需求中已经明确了要操作的具体数据,直接静态初始化即可;
- 动态初始化:手动指定数组长度,由系统给出默认初始化值,只明确元素个数;
数组默认初始化值的规律
整数类型:默认初始化值0
小数类型:默认初始化值0.0
字符类型:默认初始化值 '/u0000' 也就是 空格布尔类型:默认初始化值 false
引用数据类型:默认初始化值 null
1.4、数组的地址值
数组的地址值就是数组在内存中的位置。 一般的数组打印之后会呈现以下形式: [D@22927a81
[: 表示当前是一个数组
D: 表示当前数组里面的元素都是double类型的
@::表示一个间隔符号。(固定格式)
22927a81:才是数组真正的地址值,(十六进制)
二、数组的元素访问
2.1、数组的获取
数组的元素是通过索引访问的。数组索引从 0 开始。我们可以将数组理解为一个个整齐排列的单元格,每个单元格里面存放着一个元素。
如何获取数组中第一个元素?我们来看看代码。以此类推,我们最多能获得 数组长度-1 个元素。
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d", "e"};
// 获取数组中第一个元素
String s0 = arr[0];
System.out.println(s0); // a
}
2.2、数组的赋值
通过下面代码我们就能理解如何赋值,但是注意的是:该索引元素赋值后原先元素就不存在了。
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d", "e"};
// 赋值数组中第一个元素
arr[0]="a1";
System.out.println(arr[0]); // a1
}
2.3、数组的遍历
数组的遍历方法有很多种,我们来展示三种方法:
public static void main(String[] args) {
String[] arr = {"a", "b", "c", "d", "e"};
// 方法一:普通for循环
for(int i = 0; i <arr.length;i++){
System.out.println(arr[i]);
}
// 方法二:增强for循环
for (String s : arr) {
System.out.println(s);
}
// 方法三、foreach+lamdba表达式
Arrays.stream(arr).forEach(e-> System.out.println(e));
}
三、数组的常见问题
3.1、数组越界问题
在开发中我们经常能遇见到数组越界问题,这也是一个很常见的问题,他会抛出一个:java.lang.ArrayIndexOutOfBoundsException 异常,这个就是数组越界异常,我们来看看是如何造成的。
下列代码中,数组arr共有5个元素,那么他的数组长度为5,索引到4,如果查询索引5,则会造成数组越界异常。
四、数组的高级知识
4.1、数组在JVM中的内存
在JAM虚拟机中有如下区域分布:
- 栈:方法运行时使用的内存,比如main方法运行,进入方法栈中执行
- 堆:存储对象或者数组,new来创建的,都存储在堆内存
- 方法区:存储可以运行的class文件
- 本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关
- 寄存器:给CPU使用,和我们开发无关
一般形式的栈内存与堆内存
定义一个数组的内存图
当两个数组指向同一个小空间时,其中一个数组对小空间中的值发生了改变,那么其他数组再次访问的时候都是修改之后的结果了。
将arr1赋值给arr2,实际上是将地址值引用给了arr2,更改arr2也会影响arr1.