源本科技 | 码上会

Java 数组入门

2025/12/25
52
0

学习目标

  • 理解 Java 数组的基本概念、特性与内存模型

  • 掌握数组的声明、初始化、访问与修改方法

  • 能够处理基本类型数组和对象数组

  • 了解数组作为参数传递和返回值的使用方式

  • 认识数组的优势与局限性,为后续学习集合框架打下基础


什么是数组?

在 Java 中,数组(Array) 是一种线性数据结构,用于存储多个相同类型的元素。与 C/C++ 不同,Java 中的数组是真正的对象,隐式继承自 java.lang.Object,因此可以调用 toString()equals()hashCode() 等方法。

核心特性

  • 同类型元素:所有元素必须是同一数据类型(基本类型或引用类型)

  • 零基索引:第一个元素索引为 0

  • 固定长度:创建后大小不可变

  • 连续内存:元素在堆内存中连续存储(基本类型存值,引用类型存对象引用)

  • 内置属性:通过 .length 获取元素个数


数组的基本操作

1. 声明数组

有两种等效的声明方式:

// 方式一:C 风格(变量名后加 [])
int arr[];

// 方式二:Java 推荐风格(类型后加 [])
int[] arr;

注意:此时仅声明了引用变量,并未分配实际内存空间。


2. 初始化数组

方法一:使用 new 关键字(动态分配)

int[] numbers = new int[5]; // 创建长度为 5 的整型数组
  • 所有元素自动初始化:

    • 数值类型 → 0

    • 布尔类型 → false

    • 引用类型 → null

方法二:数组字面量

// 完整写法
int[] scores = new int[]{90, 85, 78, 92};

// 简化写法(推荐)
int[] scores = {90, 85, 78, 92};

适用于编译时已知元素值的场景。


3. 访问与修改元素

int[] arr = {10, 20, 30};

// 读取
System.out.println(arr[0]); // 输出: 10

// 修改
arr[1] = 25; // 将第二个元素改为 25

// 获取长度
int len = arr.length; // len = 3

越界风险:访问 arr[-1]arr[3](当长度为 3 时)会抛出 ArrayIndexOutOfBoundsException


4. 遍历数组

使用传统 for 循环

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

使用增强 for 循环

for (int value : arr) {
    System.out.println(value);
}

for-each 更简洁,但无法获取索引或修改原数组(对基本类型而言)。


示例:基本类型数组

public class ArrayDemo {
    public static void main(String[] args) {
        // 声明并初始化
        int[] arr = {40, 55, 63, 17, 22};

        // 遍历输出
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

输出:

40 55 63 17 22 

对象数组

数组不仅可以存储基本类型,还能存储对象引用

示例:学生信息数组

class Student {
    public int rollNo;
    public String name;

    Student(int rollNo, String name) {
        this.rollNo = rollNo;
        this.name = name;
    }
}

public class StudentArray {
    public static void main(String[] args) {
        // 声明并分配内存(5 个 Student 引用)
        Student[] students = new Student[5];

        // 实例化每个对象
        students[0] = new Student(1, "张三");
        students[1] = new Student(2, "李四");
        students[2] = new Student(3, "王五");
        students[3] = new Student(4, "赵六");
        students[4] = new Student(5, "钱七");

        // 遍历输出
        for (int i = 0; i < students.length; i++) {
            System.out.println("学号 " + students[i].rollNo + ": " + students[i].name);
        }
    }
}

输出:

学号 1: 张三
学号 2: 李四
学号 3: 王五
学号 4: 赵六
学号 5: 钱七

注意:new Student[5] 只创建了 5 个 null 引用,必须逐个 new Student(...) 才能使用。


数组作为方法参数

Java 中数组以引用传递方式传入方法(即传递的是数组在堆中的地址)。

public class ArrayPassing {
    public static void main(String[] args) {
        int[] data = {3, 1, 2, 5, 4};
        int total = calculateSum(data); // 传入数组
        System.out.println("总和: " + total);
    }

    public static int calculateSum(int[] arr) {
        int sum = 0;
        for (int num : arr) {
            sum += num;
        }
        return sum;
    }
}

输出:

总和: 15

方法内对数组元素的修改会影响原始数组(因为是同一块内存)。


从方法返回数组

方法可以返回一个数组:

public class ArrayReturn {
    public static void main(String[] args) {
        int[] result = createArray();
        for (int val : result) {
            System.out.print(val + " ");
        }
    }

    public static int[] createArray() {
        return new int[]{1, 2, 3}; // 直接返回新数组
    }
}

输出:

1 2 3 

优势与局限性

优势

优势

说明

O(1) 随机访问

通过索引直接定位元素,效率极高

内存紧凑

连续存储,缓存友好

类型安全

编译期检查元素类型一致性

简单直观

语法清晰,易于理解和使用

局限性

问题

说明

大小固定

无法动态扩容,需手动创建新数组并复制

同质性限制

不能混合不同类型(如同时存 intString

插入 / 删除开销大

中间位置操作需移动大量元素

功能有限

无内置查找、排序、过滤等高级操作(需借助 Arrays 工具类)


重点总结

  • 数组是 Java 中的基础容器,大小固定、类型统一、索引从 0 开始

  • 声明时只创建引用,需用 new 或字面量分配内存

  • 支持基本类型和对象引用两种形式

  • 通过 .length 获取长度,越界访问抛出 ArrayIndexOutOfBoundsException

  • 数组以引用方式传递给方法,可被修改

  • 方法可返回数组,常用于批量数据处理

  • 虽然高效,但灵活性不足 —— 实际开发中常被 ArrayList 等集合替代


思考题

  1. 为什么 Java 数组的长度是固定的?这种设计带来了哪些好处和坏处?

  2. 如果你需要一个可以动态增长的整数列表,除了手动实现“新建更大数组 + 复制”外,还有哪些标准库方案?

  3. 在多线程环境中直接共享一个数组是否安全?为什么?如何保证线程安全?