【JavaSE】数组

数组

概述

数组是多个相同类型的数据按一定顺序排列的集合,并使用一个名字命名,通过编号的方式对这些数据进行统一的管理。

数组中的概念:数组名、下标(索引)、元素、数组的长度。

特点

1. 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,即包括基本数据类型和引用数据类型。

2. 创建数组对象是会在内存中开辟一整块连续的空间,占据空间的大小,取悦于数组的长短和数组中元素的类型。

3. 数组中的元素在内存中是依此紧密排列的、有序的。

4. 数组一旦初始化完成,其长度就确定了。数组长度一旦确定,就不能进行修改。

5. 直接通过下标(或索引)的方式调用指定位置的元素,速度很快。

6. 数组名中引用的是这块连续空间的首地址。

分类

按照元素的类型分类:基本数据类型元素的数组和引用数据类型元素的数组;

按照数组的维数分类:一维数组、二维数组 . . . n维数组。

一维数组

声明和初始化

// 方式一
int[] a; // 数组的声明
a = new int[]{1, 2, 3, 4}; // 数组的初始化

// 方式二
int[] b; // 数组的声明
b = new int[4]; // 数组的初始化

// 方式三、方式四
// 把方式一的声明和初始化合并
int[] a = new int[]{1, 2, 3, 4};
int[] b = new int[4];

// 其他方式,也就是不按照完全规范但正确的方式
int a[] = new int[4];
int[] b = {1, 2, 3}; // 类型推断

// 错误方式
int[] a = new int[4]{1, 2, 3, 4}

动态初始化:数组变量的赋值与数组元素的赋值分开进行。

静态初始化:数组变量的赋值与数组元素的赋值同时进行。

无论是怎么样的初始化方式,一旦初始化完成,那么数组的长度就确定了。

数组元素的调用

使用“数组名[下标]”的方式来对数组元素进行调用。

int[] a = new int[]{1, 2, 3, 4};
System.out.println(a[0]);
System.out.println(a[1]);
System.out.println(a[1]);
System.out.println(a[1]);

// 输出的结果依此是1,2,3,4
// 所谓下标,即元素放置的位置
// 第一个元素的位置为0,依此加一

数组的长度

使用数组名.length来获取。

int[] a = new int[10];
System.out.println(a.length);

注意获取的长度是数组的总长度,而不是已经使用的长度;也就是说一旦初始化完成,那么获取的长度就是一个定值,始终不会改变。

数组的遍历

利用一个简单的for循环即可。

数组元素的默认初始化值

整型数组:0

浮点型数组:0.0

布尔类型:0或者是‘\u0000’

字符类型:false

引用类型:null

* 数组的内存解析

JVM内存划分

为了提高运算效率,就对空间进行了不同区域的划分,并将每一片区域都赋予了特定处理数据的方式和内存管理方式。

区域名称作用

虚拟机栈

用于存储正在执行的每个Java方法的局部变量表等。局部变量表存储了编译器可知长度的各种基本数据类型、对象引用。当方法执行完毕之后,自动释放内存。
堆内存存储对象(包括数组对象)。使用new来创建的部分存储在堆内存中。
方法区存储已被虚拟机加载的类信息、常量(静态变量)、即时编译器编译后的代码等数据。
本地方法栈

当程序中调用了native的本地方法时,本地方法执行期间的内存区域。

程序计数器

程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址。

 JVM正是将内存划分为以上5个区域,与当前数组相关的内存结构是虚拟机栈和堆内存:

int[] arr = new int[]{1, 2, 3};
// 虚拟机栈中存放的是方法中声明的局部变量,如上述代码的arr
// 堆内存中存放的是数组的实体(即数组中的所有元素),如上述代码的1、2、3

一维数组的内存解析

基本使用

如图对于一个a数组来说,首先将a存储在栈中;然后new了一个数组之后使是在堆中有一个连续内存的数据,堆中数据的首地址再返回给a,使其有一个对应关系。 

两个变量指向一个内存空间
int[] a = new int[]{1, 2, 3, 4};
int[] b = a;
b[1] = 10;

由图可知,当一个变量赋值给另一个变量之后,两者使用的是同一块内存空间,这就导致操作b的同时a也会做同样的改变,而操作a的时候b也会做同样的改变,因此要特别注意。

二维数组

概述

对于二维数组的理解,可以是看作是一维数组array1又作为另一个一维数组array2的元素而存在。

其实,从数组底层的运行机制来看,并没有多维数组,而是一维套一维,这在内存解析中可以形象感受到。

声明和初始化

静态初始化

// 所谓静态初始化,就是数组变量的赋值与数组元素的赋值同时进行
int[][] a = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8, 9}};

 动态初始化

// 所谓动态初始化,就是数组变量的赋值与数组元素的赋值分开进行

// 方式一
int[][] a = new int[3][4];

// 方式二:只给第一个括号赋值,不给第二个赋值
// 具体原因在内存解析会详细讲到
// 二维数组和多维数组相同,都可以空出最后一个括号不予赋值,但是使用时就要先new再赋予大小
int[][] a = new int[3][];
a[0] = new int[x+1]; // 使用a[0][x]时就要进行此步骤

 其他方式

// 其他方式
int a[][] = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8, 9}};
int[] a[] = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8, 9}};
int[][] a = {{1, 2, 3}, {4, 5}, {6, 7, 8, 9}}; // 类型推断

 数组元素的调用

和一维数组类似,是“数组名[下标][下标]

int[][] a = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8, 9}};

// 想要输出4,那么发现他是第二个大括号的第一个元素
// 因此调用其下标就是:a[1][0]

//  想要输出9,那么发现他是第三个大括号的第四个元素
// 因此调用其下标就是:a[2][3]

数组的长度

和一维数组相同,只不过如果是数组名,那么获取的是外层元素的个数;

如果是数组名[],那么获取的是某个外层元素包含的内层元素的个数。

数组的遍历

领用for循环嵌套即可。

数组元素的默认初始化值 

int[][] a = new int[3][2];
a[0];
a[0][0];
// 输出的结果分别是一个地址、0

// 外层元素:默认存储地址值
// 内层元素:默认与一维数组元素的不同类型的默认值规定相同

int[][] a = new int[2][];
a[0];
a[0][0];
// 输出结果是null,空指针报错

// 外层元素:默认存储null
// 内层元素:不存在,调用就会报错(NullPointerException)

* 数组的内存解析 

形象理解二维数组的内存放置

例一
int[][] a = new int[3][2];

例二
        int[][] a = new int[3][];
        a[0] = new int[4];
        a[1] = new int[3];
        a[2] = new int[2];

举例一 

        String[][] a = new String[3][2];
        int[][] b = new int[4][];
        b[1] = new int[5];
        b[1][1] = 1;
        b[2][2] = 1; // 报错

通过上述内存表示可以得知,一个二维数组就是一个一维数组中的每个元素又是一个数组而已。初学阶段可能觉得比较难以理解,但是慢慢随着学习就可以很轻松理解这个。

值得注意是,如果在初始化时,内外层全部初始化,那么就会形成a数组这样的内存情况;如果只初始化外层,那么就会形成b数组这样的内存情况,当使用具体元素时,再进行new一个新的数组当作b数组的一个元素即可。

杂记

赋值与复制

所谓赋值,就是将一个数组赋值给另一个数组,即:

int[] a = new int[]{1, 2, 3};
int[] b = a;

赋值带来的坏处就是操作a的同时b也会受到影响。

所谓复制,就是创建一个新的内存空间,将前一个内存空间的值赋给新创建的内存空间,即:

int[] a = new int[]{1, 2, 3};
int[] b = new int[a.length];
for(int i = 0; i < a.length; i++) {
       b[i] = a[i];
}

复制可以消除赋值带来的影响。

数组为啥要从0开始编号?

数组的索引,表示了数组元素距离首地址的偏离量。因为第一个元素的地址与首地址相同,所以偏离量就是0,即从0开始。

  • 21
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王彬泽

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

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

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

打赏作者

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

抵扣说明:

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

余额充值