Java 数组
1. 何为数组(Array)
定义:
数组是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,通过数组下标或索引的方式对这些数据进行统一管理。例如全班同学的数学成绩就可以构成一个数组。

特点:
- 数组属于引用数据类型,而数组中的元素可以是
任何数据类型
,包括基本数据类型和引用数据类型。 - 数组中的元素在内存中是依次紧密排列的,有序的。
- 数组的下标从0开始,范围是[0, 数组的长度-1],可以通过数组下标的方式访问指定位置的元素。
- 数组会开辟内存中的一整块连续空间。占据的空间的大小,取决于数组的长度和数组中元素的类型。
- 数组名中引用的是这块连续空间的首地址。
- 数组一旦初始化完成,其长度就是确定的。数组的长度一旦确定,就不能修改。
分类:
(1)按照元素类型分:
- 基本数据类型元素的数组:每个元素位置存储基本数据类型的值
- 引用数据类型元素的数组:每个元素位置存储对象的首地址
(2)按照维度分:
- 一维数组:存储一组数据
- 二维数组:存储多组数据,相当于二维表,一行代表一组数据,只是这里的二维表每一行长度不要求一样。
2. 一维数组
2.1 一维数组的声明
语法格式:
//推荐
元素的数据类型[] 一维数组的名称;
//不推荐
元素的数据类型 一维数组名[];
举例:
int[] arr;
int arr1[];
double[] arr2;
String[] arr3; //引用类型变量数组
Java语言中声明数组时不能指定其长度(数组中元素的个数)。 例如: int a[5]; //非法
2.2 一维数组的初始化
2.2.1 静态初始化
-
如果数组变量的初始化和数组元素的赋值操作同时进行,那就称为静态初始化。
-
静态初始化,本质是用静态数据(编译时已知)为数组初始化。此时数组的长度由静态数据的个数决定。
静态初始化格式1:
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,...};
或
数据类型[] 数组名;
数组名 = new 数据类型[]{元素1,元素2,元素3,...};
静态初始化格式2:
数据类型[] 数组名 = {元素1,元素2,元素3...};//必须在一个语句中完成,不能分成两个语句写
举例:
int[] arr = new int[]{1,2,3,4,5};//正确
int[] arr1;
arr1 = new int[]{1,2,3,4,5};//正确
int[] arr2 = {1,2,3,4,5};//正确
int[] arr3;
arr3 = {1,2,3,4,5};//错误
2.2.2 动态初始化
数组变量的初始化和数组元素的赋值操作分开进行,即为动态初始化。
动态初始化中,只确定了元素的个数(即数组的长度),而元素值此时只是默认值,还并未真正赋自己期望的值。真正期望的数据需要后续单独一个一个赋值。
动态初始化格式:
数据类型[] 数组名 = new 数据类型[长度];
或
数据类型[] 数组名;
数组名 = new 数据类型[长度];
注意:数组长度一旦指定,不可更改
举例:
// 正确写法
int[] arr = new int[5];
int[] arr;
arr = new int[5];
// 错误写法
// int[] arr = new int[5]{1,2,3,4,5}
// 后面有{}指定元素列表,就不需要在[]中指定元素个数了。
2.3 一维数组的应用
(1)获取数组长度
数组名.length
(2)访问数组元素
数组名[索引/下标]
举例
public class ArrayTest {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
System.out.println("arr数组的长度:" + arr.length);
System.out.println("arr数组的第1个元素:" + arr[0]);
System.out.println("arr数组的第2个元素:" + arr[1]);
System.out.println("arr数组的第3个元素:" + arr[2]);
System.out.println("arr数组的第4个元素:" + arr[3]);
System.out.println("arr数组的第5个元素:" + arr[4]);
//修改第1个元素的值
arr[0] = 100;
System.out.println("arr数组的第1个元素:" + arr[0]);
}
}
(3)一维数组的遍历
使用for循环可以遍历数组元素
public class ArrayTest2 {
public static void main(String[] args) {
int[] arr = new int[5];
System.out.println("arr数组的长度:" + arr.length);
System.out.print("存储数据到arr数组之前:[");
for (int i = 0; i < arr.length; i++) {
if(i==0){
System.out.print(arr[i]);
}else{
System.out.print("," + arr[i]);
}
}
System.out.println("]");
for (int i = 0; i < arr.length; i++) {
arr[i] = (i+1) * 2;
}
System.out.print("存储数据到arr数组之后:[");
for (int i = 0; i < arr.length; i++) {
if(i==0){
System.out.print(arr[i]);
}else{
System.out.print("," + arr[i]);
}
}
System.out.println("]");
}
}
// 运行结果
// arr数组的长度:5
// 存储数据到arr数组之前:[0,0,0,0,0]
// 存储数据到arr数组之后:[2,4,6,8,10]
2.4 数组元素的默认值
数组是引用类型,当使用动态初始化方式创建数组时,元素值只是默认值。对于基本数据类型而言,默认初始化值各有不同。对于引用数据类型而言,默认初始化值为null

public class ArrayTest3 {
public static void main(String argv[]){
int a[]= new int[5];
System.out.println(a[3]); //a[3]的默认值为0
}
}
2.5 数组的内存分析
2.5.1 Java虚拟机的内存划分
我们先初步领略下JVM的架构图(尚硅谷宋红康)

区域名称 | 作用 |
---|---|
虚拟机栈 |
用于存储正在执行的每个Java方法的局部变量表 等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放。 |
堆内存 |
存储对象(包括数组对象),new创建的,都存储在堆内存。 |
方法区 |
存储已被虚拟机加载的类信息、常量、(静态变量)、即时编译器编译后的代码等数据。 |
本地方法栈 | 当程序中调用了native的本地方法时,本地方法执行期间的内存区域 |
程序计数器 | 程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址 |
2.5.2 一维数组在内存中的存储
public static void main(String[] args) {
int[] arr = new int[4];
System.out.println(arr);//[I@4eec7777
}

具体细节:
- main()方法进入方法栈
- 创建数组,JVM会在堆内存中开辟连续空间,用以存储数组
- 数组在内存中会有自己的内存地址,以十六进制数表示
- 数组中有4个元素,int默认值为0
- JVM将数组的内存首地址赋值给引用类型变量arr(即数组名)
变量arr保存的是数组内存中的地址,而不是一个具体的数值,因此称为引用数据类型
数组下标从0开始,是因为第一个元素距离数组首地址间隔0个单元格。
当把一个数组名赋给另一个数组名时,此时两个数组变量本质上代表同一个数组,数组名都指向同一个内存地址
public static void main(String[] args) {
int[] arr1 = {1,2,3,4,5};
int[] arr2 = arr;
System.out.println(arr1);//[I@4eec7777
System.out.println(arr2);//[I@4eec7777
}
[I@4eec7777 中 [表示一维数组,I表示int类型,@后的值为内存的hash值
2.5.3 常见异常
(1)数组下标越界异常
当访问数组元素时,下标指定超出[0, 数组名.length-1]的范围时,就会出现数组下标越界异常:ArrayIndexOutOfBoundsException。在实际开发中,我们一定要避免出现这种情况。
public class ArrayTest4 {
public static void main(String[] args) {
int[] arr = {1,2,3};
// System.out.println("最后一个元素:" + arr[3]);//错误,下标越界
// System.out.println("最后一个元素:" + arr[arr.length]);//错误,下标越界
System.out.println("最后一个元素:" + arr[arr.length-1]);//正确
}
}
(2)空指针异常
public class ArrayTest5 {
public static void main(String[] args) {
//定义数组
int[][] arr = new int[3][];
System.out.println(arr[0][0]);//NullPointerException
}
}
因为此时数组的每一行还未分配具体存储元素的空间,arr[0]是null,此时访问arr[0][0]会抛出NullPointerException
空指针异常。
3. 二维数组
二维数组可以想象成一个棋盘,由行和列组成,每行就是一个一维数组。
3.1 二维数组声明
二维数组声明的语法格式:
//推荐
元素的数据类型[][] 二维数组的名称;
//不推荐
元素的数据类型 二维数组名[][];
//不推荐
元素的数据类型[] 二维数组名[];
3.2 二维数组初始化
3.2.1 静态初始化
// 推荐写法
int[][] arr = {{1,2,3},{4,5,6},{7,8,9,10}};//声明与初始化必须在一句完成
int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};
int[][] arr;
arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};
arr = new int[3][3]{{1,2,3},{4,5,6},{7,8,9,10}};//错误,静态初始化右边new 数据类型[][]中不能写数字
注意:一种特殊写法情况:int[] x,y[]; x是一维数组,y是二维数组。
3.2.2 动态初始化
如果二维数组的每一个数据,甚至是每一行的列数,需要后期单独确定,那么就只能使用动态初始化方式了。动态初始化方式分为两种格式:
格式1:规则二维表:每一行的列数是相同的
//(1)确定行数和列数
数据类型[][] 二维数组名 = new 数据类型[m][n];
//(2)再为元素赋新值
二维数组名[行下标][列下标] = 值;
其中,m表示这个二维数组有多少个一维数组(行数),n表示每一个一维数组的元素有多少个(列数)
格式2:不规则:每一行的列数不一样
//(1)先确定总行数
数据类型[][] 二维数组名 = new 数据类型[总行数][];
//此时只是确定了总行数,每一行里面现在是null
//(2)再确定每一行的列数,创建每一行的一维数组
二维数组名[行下标] = new 数据类型[该行的总列数];
//此时已经new完的行的元素就有默认值了,没有new的行还是null
//(3)再为元素赋值
二维数组名[行下标][列下标] = 值;
举例:
/*
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5
*/
public class TwoDimensionaArrayTest1 {
public static void main(String[] args){
//1、声明一个二维数组,并且确定行数
//因为每一行的列数不同,这里无法直接确定列数
int[][] arr = new int[5][];
//2、确定每一行的列数
for(int i=0; i<arr.length; i++){
/*
arr[0] 的列数是1
arr[1] 的列数是2
arr[2] 的列数是3
arr[3] 的列数是4
arr[4] 的列数是5
*/
arr[i] = new int[i+1];
}
//3、确定元素的值
for(int i=0; i<arr.length; i++){
for(int j=0; j<arr[i].length; j++){
arr[i][j] = i+1;
}
}
//4、遍历显示
for(int i=0; i<arr.length; i++){
for(int j=0; j<arr[i].length; j++){
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
}
3.3 二维数组的应用
(1)获取数组长度
二维数组名.length
(2)访问数组元素
二维数组名[行下标][列下标]
(3)二维数组遍历
for(int i=0; i<二维数组名.length; i++){ //二维数组对象.length
for(int j=0; j<二维数组名[i].length; j++){//二维数组行对象.length
System.out.print(二维数组名[i][j]);
}
System.out.println();
}
例题: 使用二维数组打印一个 10 行杨辉三角。
提示:
-
第一行有 1 个元素, 第 n 行有 n 个元素
-
每一行的第一个元素和最后一个元素都是 1
-
从第三行开始, 对于非第一个元素和最后一个元素的元素。即:
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
public class YangHuiTest {
public static void main(String[] args) {
//1. 动态初始化的方式创建二维数组
int[][] yangHui = new int[10][];
for (int i = 0; i < yangHui.length; i++) {
yangHui[i] = new int[i + 1];
//2. 给数组元素赋值
// 2.1 给外层数组元素中的首元素和末元素赋值
yangHui[i][0] = yangHui[i][i] = 1;
//2.2 给外层数组元素中的非首元素和非末元素赋值(难)
//if(i > 1){ //从 i == 2 开始执行
for(int j = 1;j < yangHui[i].length - 1;j++){ //非首元素和非末元素的角标范围
yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
}
//}
}
//3. 遍历二维数组
for (int i = 0; i < yangHui.length; i++) {
for (int j = 0; j < yangHui[i].length; j++) {
System.out.print(yangHui[i][j] + "\t");
}
System.out.println();
}
}
}
3.4 二维数组内存解析
二维数组本质上是元素类型是一维数组的一维数组。
int[][] arr = {
{1},
{2,2},
{3,3,3},
{4,4,4,4},
{5,5,5,5,5}
};

4. Arrays工具类的使用
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组的各种方法。
(1)打印数组元素:static String toString(int[] a)
返回元素列表,括在方括号("[]")中,相邻元素用字符 ", "(逗号加空格)分隔。形式为:[元素1,元素2,元素3···]
import java.util.Arrays;
public class ArrayToStringTest {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
System.out.println("arr = " + Arrays.toString(arr));
// arr = [1, 2, 3, 4, 5, 6]
}
}
注意:多维数组打印使用Arrays.deepToString()
(2)数组排序
static void sort(int[] a)
:将a数组按照从小到大进行排序static void sort(int[] a, int fromIndex, int toIndex)
:将a数组的[fromIndex, toIndex)部分按照升序排列static void sort(Object[] a)
:根据元素的自然顺序对指定对象数组按升序进行排序。static <T> void sort(T[] a, Comparator<? super T> c)
:根据指定比较器产生的顺序对指定对象数组进行排序。
import java.util.Arrays;
public class ArraySortTest {
public static void main(String[] args) {
int[] arr = {3, 2, 5, 1, 6};
System.out.println("排序前" + Arrays.toString(arr));// 排序前[3, 2, 5, 1, 6]
Arrays.sort(arr);
System.out.println("排序后" + Arrays.toString(arr));//排序后[1, 2, 3, 5, 6]
}
}
(3)二分查找
static int binarySearch(int[] a, int key)
static int binarySearch(Object[] a, Object key)
要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数。
import java.util.Arrays;
public class ArrayBinarySearchTest {
public static void main(String[] args) {
int[] arr = {1,3,5,7,9,20,108};
System.out.println(Arrays.binarySearch(arr, 9));// 4
}
}
(4)比较两个数组是否相等
static boolean equals(int[] a, int[] a2)
:比较两个数组的长度、元素是否完全相同static boolean equals(Object[] a,Object[] a2)
:比较两个数组的长度、元素是否完全相同
import java.util.Arrays;
public class ArrayEqualsTest {
public static void main(String[] args) {
int[] arr1 = {1,3,5,7,9,20,108};
int[] arr2 = {1,2,3,4,5,6,7};
int[] arr3 = {1,2,3,4,5,6,7};
System.out.println(Arrays.equals(arr1,arr2));// false
System.out.println(Arrays.equals(arr2,arr3));// true
}
}
(5)数组填充
static void fill(int[] a, int val)
:用val值填充整个a数组static void fill(Object[] a,Object val)
:用val对象填充整个a数组static void fill(int[] a, int fromIndex, int toIndex, int val)
:将a数组[fromIndex,toIndex)部分填充为val值static void fill(Object[] a, int fromIndex, int toIndex, Object val)
:将a数组[fromIndex,toIndex)部分填充为val对象
import java.util.Arrays;
public class ArrayFillTest {
public static void main(String[] args) {
int[] arr = new int[5];
Arrays.fill(arr,2);
System.out.println(Arrays.toString(arr));// [2, 2, 2, 2, 2]
int[] arr1 = new int[10];
Arrays.fill(arr1,2,8,10);
System.out.println(Arrays.toString(arr1));// [0, 0, 10, 10, 10, 10, 10, 10, 0, 0]
}
}
本文作者:-Miao酱-
本文链接:https://www.cnblogs.com/miaotechisland/p/18634941
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步