Skip to content

Java数组完全指南:定义、操作与内存分析

一、核心知识点

1. 数组概述

定义:数组是一个容器,本身属于引用类型

作用:一次存储多个数据

特点

  • 定长:定义数组时长度确定,后续不能更改
  • 既能存储基本类型,也能存储引用类型的数据

2. 数组的定义方式

2.1 动态初始化

java
数据类型[] 数组名 = new 数据类型[数组长度];
数据类型 数组名[] = new 数据类型[数组长度];

格式说明

  • 等号左边的数据类型:规定数组中元素的类型
  • []:代表数组
  • 数组名:见名知意
  • new:创建数组
  • new后面的数据类型:要和等号左边的数据类型一致
  • [数组长度]:给数组规定长度,最多能存多少个数据

2.2 静态初始化

java
数据类型[] 数组名 = new 数据类型[]{元素1,元素2...};
数据类型 数组名[] = new 数据类型[]{元素1,元素2...};

2.3 简化静态初始化(最常用)

java
数据类型[] 数组名 = {元素1,元素2...};

代码示例

java
public class Demo01Array {
    public static void main(String[] args) {
        int[] arr1 = new int[3];
        String[] arr2 = new String[3];
        
        int[] arr3 = {1,2,3,4,5};
        String[] arr4 = {"努尔哈赤","皇太极","顺治","康熙","雍正","乾隆","嘉庆","道光","咸丰","同治","光绪","宣统"};
    }
}

3. 数组的基本操作

3.1 获取数组长度

java
数组名.length

注意:数组中的length是一个属性,不是方法

java
public class Demo02Array {
    public static void main(String[] args) {
        int[] arr = {2,21,23,341,4,4,3,3,5,65,67,7,7};
        System.out.println(arr.length);
    }
}

3.2 索引

概述:元素在数组中的位置(编号、下标)

特点

  • 从0开始,最大索引是 数组长度-1
  • 索引是唯一的

索引示意图

3.3 存储元素

java
数组名[索引值] = 元素;
java
public class Demo03Array {
    public static void main(String[] args) {
        int[] arr = new int[3];
        arr[0] = 100;
        arr[1] = 200;
        arr[2] = 300;
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

3.4 获取元素

java
数组名[索引值]

注意

  • 数组不能直接输出数组名,因为直接输出数组名会输出数组在内存中的地址值
  • 地址值:引用类型数据在内存中保存的唯一编号

数组地址值

3.5 遍历数组

概述:挨个将数组中的元素获取出来

快捷键数组名.fori

java
public class Demo05Array {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5};
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

4. 动态初始化与静态初始化的区别

对比项动态初始化静态初始化
定义时只指定元素类型和长度直接存储具体值
默认值有默认值根据存储的数据确定长度
使用场景知道元素类型和个数,但不知道具体存什么定义时就知道存什么

各类型默认值

数据类型默认值
整数0
小数0.0
字符'\u0000'(空白字符)
布尔false
引用类型null

5. 数组常见异常

5.1 数组索引越界异常

异常名称ArrayIndexOutOfBoundsException

出现原因:操作的索引超出了数组的索引范围

索引越界异常

5.2 空指针异常

异常名称NullPointerException

出现原因:如果一个引用类型为null,再操作这个引用类型数据,就会出现空指针异常

java
public class Demo07Array {
    public static void main(String[] args) {
        int[] arr = new int[3];
        System.out.println(arr.length);
        arr = null;
        System.out.println(arr.length);
    }
}

空指针异常

6. 内存分析

6.1 Java内存划分

内存区域作用
堆(Heap)保存引用类型的数据,每new一次就开辟一个空间,自动分配地址值
栈(Stack)运行方法,方法的运行都会进栈运行
方法区(Method Area)保存类的信息以及类中成员的信息
本地方法栈(Native Method Stack)运行本地方法(带native关键字的方法)
寄存器(PC Register)和CPU有关

内存划分

6.2 一个数组内存图

一个数组内存图

6.3 两个数组内存图

创建两个数组时产生了不同的空间,修改一个空间中的数据不会影响另外一个空间的数据。

两个数组内存图

6.4 两个数组指向同一片内存空间

arr2不是重新创建出来的,而是arr直接赋值过去的,此时arr和arr2指向同一片空间,操作同一个数组。

两个数组指向同一空间

7. 数组扩容

数组定义后长度不能改变,所谓的"扩容"实际上是创建一个更大的新数组,将原数组元素复制过去。

java
public class Demo04Array {
    public static void main(String[] args) {
        int[] arr1 = {1,2,3};
        int[] arr2 = new int[5];

        for (int i = 0; i < arr1.length; i++) {
            arr2[i] = arr1[i];
        }

        arr1 = arr2;

        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]);
        }
    }
}

数组扩容


二、常见面试题

1. 数组的特点是什么?⭐

答案

  1. 定长:数组一旦创建,长度不能改变
  2. 可以存储基本类型和引用类型
  3. 数组本身是引用类型
  4. 数组元素在内存中是连续存储的
  5. 通过索引访问元素,效率高

2. 动态初始化和静态初始化有什么区别?⭐⭐

答案

对比项动态初始化静态初始化
定义方式new 数据类型[长度]{元素1,元素2...}
元素值使用默认值直接指定具体值
使用场景只知道元素个数,不知道具体值定义时就知道具体值

3. 数组索引越界异常是什么原因造成的?如何避免?⭐⭐

答案

  • 原因:访问的索引超出了数组的有效索引范围(0 到 length-1)
  • 避免方法
    1. 在访问前检查索引是否在有效范围内
    2. 使用增强for循环遍历
    3. 使用 数组名.length 获取长度进行边界判断

4. 什么是空指针异常?在数组操作中什么情况会出现?⭐⭐

答案

  • 定义:当引用类型变量为null时,尝试调用其方法或访问其属性,就会抛出NullPointerException
  • 数组中出现的情况
    1. 数组引用被赋值为null后,继续访问数组元素或属性
    2. 数组元素为引用类型且为null时,调用该元素的方法

5. 数组在内存中是如何存储的?⭐⭐⭐

答案

  1. 数组是引用类型,数组引用变量存储在栈中
  2. 数组元素存储在堆中
  3. 数组引用变量存储的是堆中数组的首地址
  4. 数组元素在堆中是连续存储的
  5. 每个数组对象都有一个length属性

6. 如何理解数组的"定长"特性?如果需要动态扩容怎么办?⭐⭐⭐

答案

  • 定长:数组一旦创建,其长度就固定不变
  • 扩容方案
    1. 创建一个更大的新数组
    2. 将原数组元素复制到新数组
    3. 将原数组引用指向新数组
    4. 实际开发中可使用 Arrays.copyOf()System.arraycopy()

7. 数组的默认值是什么?⭐

答案

数据类型默认值
byte, short, int, long0
float, double0.0
char'\u0000'
booleanfalse
引用类型(类、接口、数组)null

8. 以下代码输出结果是什么?⭐⭐

java
int[] arr1 = {1, 2, 3};
int[] arr2 = arr1;
arr2[0] = 100;
System.out.println(arr1[0]);

答案:输出 100

解析:arr2 = arr1 是将arr1的地址值赋给arr2,两个引用指向同一个数组对象,修改arr2的元素会影响arr1。


三、实用代码片段

1. 获取数组最大值

java
public class Demo01GetMax {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (max < arr[i]) {
                max = arr[i];
            }
        }
        System.out.println("最大值:" + max);
    }
}

2. 统计符合条件的元素个数

java
import java.util.Random;

public class Demo02Count {
    public static void main(String[] args) {
        int[] arr = new int[10];
        Random rd = new Random();
        int count = 0;
        
        for (int i = 0; i < arr.length; i++) {
            arr[i] = rd.nextInt(101);
        }
        
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] % 3 == 0 && arr[i] % 5 == 0 && arr[i] % 7 != 0) {
                count++;
            }
        }
        System.out.println("符合条件的个数:" + count);
    }
}

3. 格式化输出数组

java
public class Demo03Print {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                System.out.print(arr[i] + "]");
            } else {
                System.out.print(arr[i] + ", ");
            }
        }
    }
}

输出[1, 2, 3, 4]

4. 查找元素索引

java
import java.util.Scanner;

public class Demo04Search {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44, 55, 66};
        Scanner sc = new Scanner(System.in);
        int data = sc.nextInt();
        int flag = 0;

        for (int i = 0; i < arr.length; i++) {
            if (data == arr[i]) {
                System.out.println("找到元素,索引为:" + i);
                flag++;
            }
        }

        if (flag == 0) {
            System.out.println(-1);
        }
    }
}

5. 数组扩容模板

java
public class ArrayExpand {
    public static void main(String[] args) {
        int[] oldArr = {1, 2, 3};
        int newLength = oldArr.length * 2;
        int[] newArr = new int[newLength];
        
        for (int i = 0; i < oldArr.length; i++) {
            newArr[i] = oldArr[i];
        }
        
        oldArr = newArr;
    }
}

四、经典练习题

练习1:获取数组最大值(基础题)

题目:定义一个数组,存储若干整数,找出最大值。

思路

  1. 定义数组,存储数据
  2. 定义变量max,初始值为数组第一个元素
  3. 遍历数组,比较每个元素与max
  4. 如果元素大于max,更新max
  5. 输出max

参考代码

java
public class GetMax {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (max < arr[i]) {
                max = arr[i];
            }
        }
        System.out.println(max);
    }
}

练习2:统计符合条件的元素(进阶题)

题目:随机产生10个[0,100]之间整数,统计既是3又是5,但不是7的倍数的个数。

思路

  1. 创建长度为10的数组和Random对象
  2. 产生10个随机数放入数组
  3. 遍历数组,判断条件:num % 3 == 0 && num % 5 == 0 && num % 7 != 0
  4. 符合条件则计数器加1

参考代码

java
import java.util.Random;

public class CountNumbers {
    public static void main(String[] args) {
        int[] arr = new int[10];
        Random rd = new Random();
        int count = 0;
        
        for (int i = 0; i < arr.length; i++) {
            arr[i] = rd.nextInt(101);
        }
        
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] % 3 == 0 && arr[i] % 5 == 0 && arr[i] % 7 != 0) {
                count++;
            }
        }
        System.out.println(count);
    }
}

练习3:格式化输出数组(进阶题)

题目:定义数组 int[] arr = {1,2,3,4},遍历输出为 [1,2,3,4] 格式。

思路

  1. 先输出 [
  2. 遍历数组,输出每个元素
  3. 如果不是最后一个元素,输出 ,
  4. 最后一个元素输出 ]

参考代码

java
public class PrintArray {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        System.out.print("[");
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                System.out.print(arr[i] + "]");
            } else {
                System.out.print(arr[i] + ", ");
            }
        }
    }
}

练习4:查找元素索引(进阶题)

题目:键盘录入一个整数,找出该整数在数组中的索引位置,找不到返回-1。

思路

  1. 定义数组
  2. 键盘录入要查找的数据
  3. 遍历数组,比较每个元素
  4. 找到则输出索引,找不到输出-1

参考代码

java
import java.util.Scanner;

public class SearchIndex {
    public static void main(String[] args) {
        int[] arr = {11, 22, 33, 44, 55, 66};
        Scanner sc = new Scanner(System.in);
        int data = sc.nextInt();
        int flag = 0;

        for (int i = 0; i < arr.length; i++) {
            if (data == arr[i]) {
                System.out.println(i);
                flag++;
            }
        }

        if (flag == 0) {
            System.out.println(-1);
        }
    }
}

练习5:键盘录入学员姓名(综合题)

题目:用一个数组存储本组学员的姓名,从键盘输入,并遍历显示。

思路

  1. 创建指定长度的String数组
  2. 使用Scanner循环录入姓名
  3. 遍历数组输出所有姓名

参考代码

java
import java.util.Scanner;

public class StudentNames {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入学员人数:");
        int count = sc.nextInt();
        String[] names = new String[count];
        
        for (int i = 0; i < names.length; i++) {
            System.out.print("请输入第" + (i + 1) + "个学员姓名:");
            names[i] = sc.next();
        }
        
        System.out.println("\n学员名单:");
        for (int i = 0; i < names.length; i++) {
            System.out.println((i + 1) + ". " + names[i]);
        }
    }
}

五、学习建议

1. 学习重点

  1. 理解数组的本质:数组是引用类型,存储在堆内存中
  2. 掌握索引操作:索引从0开始,最大索引是length-1
  3. 理解内存模型:理解栈和堆的关系,理解地址值的概念
  4. 避免常见异常:索引越界和空指针是数组操作最常见的异常

2. 编程技巧

  1. 使用 数组名.fori 快速生成遍历代码
  2. 访问数组元素前,先检查索引是否有效
  3. 操作引用类型数组元素前,先判断是否为null
  4. 需要动态扩容时,考虑使用ArrayList等集合类

3. 调试技巧

  1. 直接打印数组名会输出地址值,应遍历打印元素
  2. 使用IDE的调试功能查看数组内容
  3. 遇到异常时,检查索引范围和null值

4. 扩展方向

[基于课程进度补充] 学习完数组后,建议继续学习:

  • 二维数组
  • Arrays工具类
  • ArrayList集合(动态数组)
  • 数组排序算法(冒泡、选择等)
  • 数组查找算法(二分查找)

六、知识图谱

∂dJava数组
├── 基础概念
│   ├── 定义:引用类型容器
│   ├── 特点:定长、连续存储
│   └── 作用:存储多个同类型数据

├── 初始化方式
│   ├── 动态初始化:new 数据类型[长度]
│   └── 静态初始化:{元素1, 元素2, ...}

├── 基本操作
│   ├── 获取长度:数组名.length
│   ├── 索引访问:从0开始
│   ├── 存储元素:数组名[索引] = 值
│   ├── 获取元素:数组名[索引]
│   └── 遍历:for循环

├── 常见异常
│   ├── ArrayIndexOutOfBoundsException
│   └── NullPointerException

├── 内存分析
│   ├── 栈:存储引用变量
│   ├── 堆:存储数组对象
│   └── 地址值:引用指向对象

└── 高级操作
    ├── 数组扩容
    ├── 查找元素
    └── 统计计算

七、速查表

数组定义速查

方式语法示例
动态初始化数据类型[] 数组名 = new 数据类型[长度];int[] arr = new int[5];
静态初始化数据类型[] 数组名 = {元素...};int[] arr = {1, 2, 3};

数组操作速查

操作语法示例
获取长度数组名.lengtharr.length
存储元素数组名[索引] = 值;arr[0] = 100;
获取元素数组名[索引]int num = arr[0];
遍历数组for (int i = 0; i < arr.length; i++)见代码示例

默认值速查

数据类型默认值
byte, short, int, long0
float, double0.0
char'\u0000'
booleanfalse
引用类型null