java基础
第一章 初识java
第二章 java语言基础
第三章 流程控制
第四章 数组
文章目录
前言
本章节将介绍java中的一个常用容器——数组,在使用数组后我们可以便捷的操作批量的数据。
一、认识数组
数组是一个容器,可以批量存储数据。它是相同类型的一组数据的集合(即一个数组中的数据都是同类型的)。
它在内存中是连续存储的。
于是数组的特点有:
- 一个数组内只会存储同一类型数据
- 元素是连续存储的
- 使用索引访问其中的元素
- 数组长度一旦定义就不可改变
二、数组定义
定义数组的语法格式如下:
数据类型[] 数组名 =new 数据类型[数组长度]
或
数据类型[] 数组名={元素1,元素2,……}
或
数据类型[] 数组名=new数据类型[]{元素1,元素2,……}
这里的数据类型可以是基础类型(如:int、double、char)也可以是引用类型(如:类)如:
public static void main(String[] args) {
short[] arr = new short[10];
int [] arr1 = {1,2,3,4,5,6,7,8,9,10};
double[] arr2=new double[]{1,2,3,4,5,6,7,8,9,10};
}
后面括号中的“数组长度”决定改数组能容纳的元素个数。
三、数组初始化
数组一旦创建之后,只要不是空数组(长度为0的数组),其内部元素必须初始化(必须进行赋值)。初始化的方式有两种:静态初始化、动态初始化。
1.静态初始化
静态初始化,就是由我们在创建数组时手动为数组中的每个元素赋值,其格式如下(就是上文第二、三种定义方式,但后一种不常用):
数据类型[] 数组名 = {元素1值,元素2值,……}
从上看出,就是把每个元素的初始值放到{}中并用逗号分隔,最后传递给数组,使用静态初始化的话就无需额外指定数组长度。
如:
public static void main(String[] args) {
int [] arr = {1,2,3,4,5,6,7,8,9,10};
}
2.动态初始化
动态初始化,就是让jvm虚拟机自动为数组中的元素赋初始值,这种情况下我们只需要指定数组的长度即可。格式如下:
数据类型[] 数组名 =new 数据类型[数组长度]
如:
public static void main(String[] args) {
short[] arr = new short[10];
}
当使用动态初始化时,针对不同的数据类型,虚拟机将会使用以下这些初始值:
整数 0
小数 0.0
布尔值 false
字符 ‘\u0000’(经过编码后时空白字符)
引用类型 null
四、数组操作
数组是一个存储数据的容器,那我们自然要对其中的数据(数组的元素)进行操作。接下来看一下数据的四大操作(增、删、改、查)都如何完成。
1.增
上文说到,数组创建时,会为其在内存中分配空间,这个操作只进行一次,所以一个数组的存储容量一经确定就无法改变。
所以对于数组而言不存在真正意义上的增加元素功能。
2.删
上文说到,数组创建时,会为其在内存中分配空间,这个操作只进行一次,所以一个数组的存储容量一经确定就无法改变。
所以对于数组而言不存在真正意义上的删除元素功能。
3.改,查
在程序中要访问一个数组元素,其格式如下:
数组名[索引]
前面说过数组是连续存储结构,其元素存放位置在内存中是一片连续的区域,而索引可以相当于一个位置表标识,能够取出对应位置的索引。
打个比方,就像军训时台上的人想要让某人出列,它并不需要知道那个人叫什么名字,而只需要知道数出那个人的位置(几行几列)即可。而普通数组中的元素可以理解为只有一行,所以知道想要的元素时第几个即可。
但要注意一点——数组的元素从0号开始算(即我们用索引0拿到第一个元素,用索引7拿到第八个元素)
如:
public static void main(String[] args) {
int[] arr={1,2,3,4,5,6,7,8,9,10};
System.out.println(arr[3]);
}//输出4
五、二维数组
二维数组是一种特殊的数组,前面我们了解到,数组可以存多种类型的数据,并且需要在创建数组时使用
数据类型[] 数组名 = 略
来决定该数组存储何种类型的数据。
那么,数组本身也是一种数据类型,所以这里的“数据类型”同样可以指定为一个数组,于是一个数组中就会存储数组类型的数据作为元素(有点套娃的感觉),这样的数组我们将其称之为二维数组。
这样一来我们用数组的类型声明语句来替换掉普通数组中的“数据类型”部分,就得到二维数组的定义语法
数据类型[][] 数组名 =new 数据类型[外层数组长度][内存数组长度]
如:
public static void main(String[] args) {
int[][] arr1 = new int[3][2];
int[][] arr2 ={{1,2},{3,4},{5,6}};
}
一般我们习惯把二维数组看作一个方阵,其第一个索引看作方阵的行,后一个看作列,比如有一个[3][3]的int数组:
public static void main(String[] args) {
int[][] arr1 = {{1,2,3},{4,5,6},{7,8,9}};
}
其真正在内存中存放情况如下:
但我们可以将其想象为一个方阵,如下:
于是在二维数组中的索引就相等于该方阵的行列号了:
六、数组的内存机制
为了加深对数组的理解,我们来了解一下数组在内存中具体的存储情况。
1.java内存机制概述
想要了解数组这项具体数据的内存机制,我们先要对java总体的内存机制有个了解。
java虚拟机在运行时将其使用的内存分为五个区域:栈、堆、方法区、本地方法栈、寄存器。
我们作为开发人员,需要了解其中的三个区域:栈、堆、方法区
栈
目前只要知道是控制方法调用的地方,且里面存储了:变量、基本类型数据、引用类型数据在堆中的地址
堆
目前只要知道内部存储了引用类型的数据,数组的数据
方法区
存储一些常量信息和方法信息等,其他先不介绍
2.数组在内存中存储
数组创建内存分配
我们前面提到数组的数据在内存中进行连续存储,那么现在进一步细化这个说法——其数据连续存储在内存中被称为“堆”的区域。
比如我们动态初始化一个长度为3的整形数组,则在堆中就会开辟一个空间存储这个数组的数据:
可以看到有三个整形数据被存储在堆中,并且因为使用动态初始化,三个元素都被初始化赋值为0.
那么我们在获取元素时是使用定义语句前面的arr,这个东西其实并不是数组本身,而是一个数组类型的变量,变量也是一种具体存在的东西,所以也需要占用内存,只不过他所在的是一个叫“栈”的内存区域,并且该变量内还记录了数组数据在堆中的地址。
访问堆中的数组元素
前面说过,我们使用通过告诉数组索引,来获取对应的元素,底层其实通过一个公式
要访问元素的位置=数组起始位置+索引*数组所存储数据类型大小
来进一步计算出所访问元素的位置,从而从堆内存中得到数据。其中数组起始位置由对应的数组变量记录,索引由我们使用数组时传入,数组所存储数据类型大小也是固定的(比如int类型占四个字节,表示在查找数组元素时每次以四字节为一个单位长度来查找元素)
总结
本节介绍了java中数组的使用,以及其内存机制。