完整教程:数组(Java基础语法)

数组的声明语法拆解:int[] scores;我们把这句代码分成三个部分来看:

1. int (元素类型 - Type)含义: 这部分指定了未来这个数组中,每一个“格子”里存放的数据的类型。

int 表示这个数组是一个“整型数组”,它里面的每个元素都必须是 int 类型的整数。

你也可以声明其他类型的数组:

double[] prices; (一个用来装 double 类型价格的数组)

String[] names; (一个用来装 String 类型名字的数组)

char[] letters; (一个用来装 char 类型字母的数组)

规则: 一个数组一旦被声明为某种类型,它就永远只能存放该类型的数据,不能混装。

2. [] (数组标识符)含义: 这对方括号 [] 是语法的核心,它告诉编译器:“这不是一个普通的 int 变量,而是一个能装很多个 int 的数组!”

它就像给变量贴上了一个“容器”的标签。

int scores; -> 只能装 一个 int。

int[] scores; -> 能装 一串 int。

写法的灵活性:

int[] scores; ( 推荐的写法,类型 int[] 和变量名 scores 分离,更清晰)

int scores[]; ( C/C++风格的写法,Java为了兼容也支持,但不推荐)

这两种写法在功能上完全等价,但社区和官方更推荐第一种,因为它更符合Java的“类型 变量名”的声明风格。

3. scores (变量名 - Identifier)含义: 这是我们给这个“数组引用变量”起的名字。

以后,我们就可以通过 scores 这个名字,来访问和操作这个数组了。

变量名需要遵循Java的标识符命名规范(比如不能以数字开头,不能是关键字等),通常使用有意义的小驼峰命名法

数组的初始化哪种情况用哪个?初始化方式决策依据核心思想例子动态初始化只知道长度,不知道内容“先占坑,后填数”用户输入、存放计算结果静态初始化已经知道确切内容“坑和数,一步到位”星期、月份、固定配置、测试数据1. 静态初始化 (Static Initialization)“内容驱动”的初始化

核心思想: 在创建数组的同时,就直接指定数组中要存放的具体元素内容。数组的长度由你提供元素的个数来自动决定。

适用场景: 当你已经明确知道数组里应该放哪些具体的值时,就用静态初始化。

口诀: “内容决定长度”。

完整语法:

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

示例:

int[] arr = new int[]{1, 2, 3, 4, 5};

String[] names = new String[]{"张三", "李四", "王五"};

简化语法 (更常用):

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

2. 动态初始化 (Dynamic Initialization)“长度驱动”的初始化

核心思想: 在创建数组时,只指定数组的长度,而不关心里面元素的具体内容。数组中每个元素的初始值,会由系统根据其数据类型自动分配一个默认值。

适用场景: 当你只知道需要多大的空间,但具体的值要在程序运行过程中,再慢慢填充进去时,就用动态初始化。

口诀: “长度决定内容”。

语法:

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

示例:

// 创建一个能存放5个整数的数组,所有位置的初始值都是 0

int[] numbers = new int[5];

// 创建一个能存放10个字符串的数组,所有位置的初始值都是 null

String[] userList = new String[10];

动态初始化之后,数组里填的都是默认值(int 就是 0)。给它填上我们想要的数,其实非常简单,核心就一步:通过索引定位,然后赋值。方式一:手动一个一个地填(最基础,但不常用)这就像你手动操作:

找到第1个格子(索引是0),把里面的 0 换成 10。

找到第2个格子(索引是1),把里面的 0 换成 20。

找到第3个格子(索引是2),把里面的 0 换成 30。

对应的代码:

int[] array2 = new int[3]; // 此时内容是 {0, 0, 0}

// 开始填数

array2[0] = 10; // 把 10 赋值给索引为 0 的位置

array2[1] = 20; // 把 20 赋值给索引为 1 的位置

array2[2] = 30; // 把 30 赋值给索引为 2 的位置

// 现在,array2 的内容就变成了 {10, 20, 30}

System.out.println(array2[0]); // 输出 10

System.out.println(array2[1]); // 输出 20

System.out.println(array2[2]); // 输出 30

缺点:如果数组有100个元素,你总不能写100行代码吧?太笨拙了!所以我们需要更聪明的方法。

方式二:使用 for 循环来填(最常用,最高效)这才是我们处理数组的标准方法。循环可以自动地、重复地帮我们完成“定位 -> 赋值”这个操作。

核心思路:

让循环变量 i 从 0 开始,每次循环都作为数组的索引,直到遍历完所有位置。

一个完整的例子:从键盘输入5个学生的成绩

import java.util.Scanner;

public class FillArrayExample {

public static void main(String[] args) {

// 1. 动态初始化:创建一个能装5个分数的数组,现在全是0

int[] scores = new int[5];

Scanner sc = new Scanner(System.in);

System.out.println("请输入5位学生的成绩:");

// 2. 使用 for 循环填数

// scores.length 的值是 5

// 循环会执行5次,i 的值会依次是 0, 1, 2, 3, 4

for (int i = 0; i < scores.length; i++) {

System.out.print("请输入第 " + (i + 1) + " 位学生的成绩: ");

// 关键代码在这里!

// 第一次循环 (i=0): scores[0] = 用户输入的值

// 第二次循环 (i=1): scores[1] = 用户输入的值

// ...以此类推

scores[i] = sc.nextInt();

}

System.out.println("--------------------");

System.out.println("所有学生的成绩录入完毕,如下:");

// 3. 使用另一个 for 循环来查看结果

for (int i = 0; i < scores.length; i++) {

System.out.println("第 " + (i + 1) + " 位学生的成绩是: " + scores[i]);

}

}

}

运行这个程序,你会看到:

请输入5位学生的成绩:

请输入第 1 位学生的成绩: 98

请输入第 2 位学生的成绩: 85

请输入第 3 位学生的成绩: 77

请输入第 4 位学生的成绩: 92

请输入第 5 位学生的成绩: 100

--------------------

所有学生的成绩录入完毕,如下:

第 1 位学生的成绩是: 98

第 2 位学生的成绩是: 85

第 3 位学生的成绩是: 77

第 4 位学生的成绩是: 92

第 5 位学生的成绩是: 100

数组的访问“访问”数组,主要包含两个动作:

读取数组中某个位置的元素值。

修改数组中某个位置的元素值。

这两个动作都依赖于同一个关键概念——索引 (Index)。

1. 核心概念:索引 (Index)你可以把数组想象成电影院里的一排座位,或者一栋楼里的一个个房间。

数组: 就是那一整排座位。

元素: 就是每个座位上坐着的人。

索引: 就是每个座位的编号。

索引有两条铁律,必须牢记:

索引从 0 开始:

第一个元素的索引是 0,第二个是 1,第三个是 2,以此类推。

这是一个非常非常重要的计算机编程约定,几乎所有主流语言都遵循这个规则。

最大索引是 数组长度 - 1:

如果一个数组有 5 个元素(长度为5),那么它的索引范围就是 0, 1, 2, 3, 4。最大索引是 5 - 1 = 4。

如果你试图访问超出这个范围的索引(比如 -1 或者 5),程序就会立刻崩溃,并抛出著名的 ArrayIndexOutOfBoundsException (数组索引越界异常)。

2. 访问数组的语法访问数组的语法非常简单,就是:

数组名[索引]

这个语法既可以用来读取,也可以用来修改。

代码示例:我们先创建一个数组,作为操作的对象:

// 创建一个长度为 5 的整型数组,用来存放考试成绩

int[] scores = {95, 88, 76, 99, 82};

现在,这个 scores 数组在内存中的样子是:

元素值9588769982索引012343. 读取元素 (Reading Elements)把 数组名[索引] 这个表达式放在等号的右边,或者直接用在打印语句里,就是读取操作。

public class ArrayRead {

public static void main(String[] args) {

int[] scores = {95, 88, 76, 99, 82};

// 读取第一个元素 (索引为 0)

int firstScore = scores[0];

System.out.println("第一个学生的成绩是: " + firstScore); // 输出: 95

// 读取第三个元素 (索引为 2)

int thirdScore = scores[2];

System.out.println("第三个学生的成绩是: " + thirdScore); // 输出: 76

// 读取最后一个元素 (索引为 长度-1)

// scores.length 的值是 5

int lastScore = scores[scores.length - 1]; // scores[4]

System.out.println("最后一个学生的成绩是: " + lastScore); // 输出: 82

// 错误示例:访问不存在的索引

// int errorScore = scores[5]; // 这行代码会立刻让程序崩溃!

}

}

4. 修改元素 (Modifying Elements)把 数组名[索引] 这个表达式放在等号的左边,就是修改操作(也叫赋值)。

public class ArrayModify {

public static void main(String[] args) {

int[] scores = {95, 88, 76, 99, 82};

// 打印修改前的第二个成绩

System.out.println("修改前,第二个学生的成绩是: " + scores[1]); // 输出: 88

// 修改第二个元素的值 (索引为 1)

// 把 90 这个值,存放到索引为 1 的位置上

scores[1] = 90;

// 打印修改后的第二个成绩

System.out.println("修改后,第二个学生的成绩是: " + scores[1]); // 输出: 90

// --- --- ---

// 假设第四个学生 (索引为 3) 的成绩录错了,应该是满分

scores[3] = 100;

System.out.println("订正后,第四个学生的成绩是: " + scores[3]); // 输出: 100

}

}

数组的属性length 是数组一个非常重要的内置属性,它简单、直接,但又极其有用。

1. 核心概念:length 是什么?定义: length 是每个数组对象都自带的一个属性,它表示这个数组可以容纳的元素总数。

直观理解: 它就是数组的“长度”或者“容量”。

语法: 数组名.length

返回值: 一个 int 类型的整数。

重要特性:

它是属性,不是方法: 注意 length 后面没有括号 ()。

scores.length (✔︎ 正确)

scores.length() (❌ 错误! 这会让编译器以为你在调用一个叫 length 的方法)

(这与字符串的 length() 方法不同,是初学者容易混淆的地方)

它是 final 的 (只读): 一旦数组被创建,它的长度就固定不变了。你只能读取 length 属性的值,不能修改它。

int len = scores.length; (✔︎ 正确)

scores.length = 10; (❌ 错误! 无法为最终变量length分配值)

2. length 的作用和用法length 属性最核心的用途,就是让我们的代码能够“知道”数组有多长,从而进行安全、灵活的操作。它主要用在以下两个关键场景:

场景一:获取数组的长度信息这是最直接的用法。

代码示例:

codeJava

public class ArrayLengthDemo {

public static void main(String[] args) {

// 静态初始化的数组

String[] fruits = {"Apple", "Banana", "Orange"};

int fruitCount = fruits.length;

System.out.println("水果数组的长度是: " + fruitCount); // 输出: 3

// 动态初始化的数组

int[] numbers = new int[10]; // 创建一个长度为10的数组

int numberCapacity = numbers.length;

System.out.println("数字数组的长度是: " + numberCapacity); // 输出: 10

// 空数组

double[] emptyArray = {};

System.out.println("空数组的长度是: " + emptyArray.length); // 输出: 0

}

}

场景二:数组的遍历 (最重要的用途!)遍历 (Traversal),就是从头到尾访问数组中的每一个元素。如果我们不知道数组有多长,就无法做到这一点。length 属性是实现数组遍历的关键。

问题: 如何打印出 scores 数组中的每一个成绩?

错误的方式 (硬编码):

int[] scores = {95, 88, 76, 99, 82};

System.out.println(scores[0]);

System.out.println(scores[1]);

System.out.println(scores[2]);

System.out.println(scores[3]);

System.out.println(scores[4]);

这种写法非常笨拙,如果数组有100个元素,你就要写100行。而且如果数组长度变了,代码就得重写。

正确的方式 (使用 for 循环和 .length):

public class ArrayTraversal {

public static void main(String[] args) {

int[] scores = {95, 88, 76, 99, 82, 100, 75}; // 我们可以随时增删元素

System.out.println("数组 scores 的长度是: " + scores.length); // 输出: 7

// 使用 for 循环遍历数组

// i 的范围是从 0 到 scores.length - 1

for (int i = 0; i < scores.length; i++) {

// 在循环中,i 的值会依次是 0, 1, 2, 3, 4, 5, 6

System.out.println("索引为 " + i + " 的元素是: " + scores[i]);

}

}

}

输出:

数组 scores 的长度是: 7

索引为 0 的元素是: 95

索引为 1 的元素是: 88

索引为 2 的元素是: 76

索引为 3 的元素是: 99

索引为 4 的元素是: 82

索引为 5 的元素是: 100

索引为 6 的元素是: 75

为什么这种方式好?

自动化: 循环会自动处理从第一个到最后一个的所有元素。

灵活性/自适应: 无论 scores 数组的长度变成多少(5个、10个、100个),这段遍历代码完全不需要修改,因为它总是通过 scores.length 来动态获取正确的循环次数。这让我们的代码非常健壮。

安全性: i < scores.length 这个条件,完美地保证了索引 i 的最大值只会是 scores.length - 1,从而杜绝了数组越界的风险。