一、回顾与本篇目标
上一篇你学会了循环——用 for 循环重复执行代码,用 while 循环在条件成立时持续执行。你现在可以写程序自动计算 1 到 100 的和、判断一个数是不是素数。
但如果你要存储全班 50 个学生的成绩,怎么办?定义 50 个变量?int score1, score2, score3... 那如果要计算平均分,你需要把 50 个变量一个一个写出来加起来。这显然不现实。更麻烦的是,如果学生人数是运行时才知道的(比如用户输入人数),你根本没办法提前定义那么多变量。
你需要数组——一种能一次性存储多个相同类型数据的结构。数组就像一排贴了编号的储物柜——每个柜子存一个数据,通过编号(索引)来存取。
本篇的目标:
- 理解数组是什么——连续存放的多个数据
- 学会数组的声明、初始化和访问
- 掌握用循环遍历数组
- 学会数组的常见操作:求和、最大值、查找
- 理解二维数组
二、数组是什么——一排编号的储物柜
数组是同一种类型数据的集合。你可以把数组想象成学校里一排带编号的储物柜:
- 每个柜子大小相同(都存同一种类型的数据,比如都是
int)。 - 每个柜子有一个编号(从 0 开始),叫索引或下标。
- 通过编号可以快速找到任何一个柜子里的东西。
- 柜子的总数在创建时就定好了,之后不能改变。
在 Java 中,数组是固定大小的——创建时指定长度,之后这个长度不能变。如果需要能动态增减的容器,后面会学 ArrayList。
三、数组的声明和创建
3.1 声明数组变量
语法:数据类型[] 数组名;
int[] scores; // 声明一个存放整数的数组,名字叫 scores
double[] prices; // 声明一个存放小数的数组
String[] names; // 声明一个存放字符串的数组
char[] letters; // 声明一个存放字符的数组
声明只是告诉编译器“这个变量将来会指向一个数组”,此时数组还不存在,就像你画了一个柜子区的规划图,但柜子还没造出来。
3.2 创建数组——让柜子真正存在
用 new 关键字真正创建数组,必须指定长度:
scores = new int[5]; // 创建一个长度为 5 的整数数组
prices = new double[10]; // 创建一个长度为 10 的小数数组
names = new String[3]; // 创建一个长度为 3 的字符串数组
数组创建后,每个位置都有一个默认值:
- 整数类型(
int、byte、short、long):0 - 小数类型(
float、double):0.0 - 字符类型(
char):‘\u0000’(空字符) - 布尔类型(
boolean):false - 引用类型(
String等):null(表示空,不指向任何对象)
3.3 声明和创建一步完成
int[] scores = new int[5]; // 声明并创建,长度为 5
double[] prices = new double[3]; // 声明并创建,长度为 3
String[] names = new String[4]; // 声明并创建,长度为 4
3.4 创建的同时赋值——静态初始化
如果你已经知道数组里要存什么数据,可以在创建时直接列出所有值:
int[] scores = {85, 92, 78, 95, 88}; // 长度为 5,值已填入
double[] prices = {19.9, 29.9, 39.9}; // 长度为 3
String[] fruits = {"苹果", "香蕉", "橘子"}; // 长度为 3
// 也可以先声明,再用这种方式赋值(但只能在声明的同时使用)
int[] numbers;
numbers = new int[]{10, 20, 30, 40}; // 先声明,后赋值用 new int[]{...}
使用花括号 {} 初始化时,不需要写数组长度——Java 会根据你列出的值的个数自动确定长度。
四、访问数组元素——通过索引
数组的索引从 0 开始。一个长度为 N 的数组,有效索引是 0 到 N-1。
int[] scores = {85, 92, 78, 95, 88};
// 索引: 0 1 2 3 4
// 值: 85 92 78 95 88
读取数组元素
System.out.println(scores[0]); // 85 —— 第一个元素
System.out.println(scores[1]); // 92 —— 第二个元素
System.out.println(scores[4]); // 88 —— 第五个元素(最后一个)
修改数组元素
scores[0] = 100; // 把第一个元素改成 100
scores[3] = scores[3] + 5; // 把第四个元素加 5
System.out.println(scores[0]); // 100
System.out.println(scores[3]); // 100
获取数组长度
数组有一个内置属性 length,表示数组的长度(元素个数):
int[] scores = {85, 92, 78, 95, 88};
System.out.println("数组长度:" + scores.length); // 5
注意:length 是属性,不是方法,后面不加括号。这和 String 的 length() 方法不同(后面会讲)。
数组下标越界
如果访问的索引超出了数组的有效范围,Java 会抛出 ArrayIndexOutOfBoundsException(数组下标越界异常),程序会报错并停止:
int[] scores = {85, 92, 78};
// System.out.println(scores[5]); // 运行时错误!索引 5 超出了长度 3 的范围
这是最常见的数组错误之一。记住:索引范围是 0 到 length-1。
五、遍历数组——用循环处理每个元素
数组和循环是天生的搭档。数组存数据,循环逐个处理数据。
5.1 用 for 循环按索引遍历
public class ArrayTraversal {
public static void main(String[] args) {
int[] scores = {85, 92, 78, 95, 88};
System.out.println("所有成绩:");
for (int i = 0; i < scores.length; i++) {
System.out.println("学生 " + (i + 1) + ":" + scores[i] + " 分");
}
}
}
输出:
所有成绩:
学生 1:85 分
学生 2:92 分
学生 3:78 分
学生 4:95 分
学生 5:88 分
关键点:
i = 0:从第一个元素开始。i < scores.length:严格小于长度,不能写成<=。因为长度为 5 时,最大索引是 4,i <= 5会让 i 等于 5 时访问scores[5],导致越界。i++:每次索引加 1,访问下一个元素。
5.2 用增强 for 循环(for-each)遍历
Java 提供了一种更简洁的遍历方式——增强 for 循环。你不需要手动管理索引,直接拿到每个元素的值:
int[] scores = {85, 92, 78, 95, 88};
for (int score : scores) { // 读作:对于 scores 中的每一个 score
System.out.println(score);
}
这个循环的意思是:把 scores 数组中的每个元素依次赋给变量 score,然后执行循环体。 它等价于前面的 for 循环,但更简洁。
增强 for 循环的局限:
- 你不知道当前元素的索引(想知道是第几个元素时,用普通 for 循环)。
- 你不能修改数组元素的值(修改
score变量只是修改了临时变量的副本,不影响原数组)。
5.3 两种遍历方式的选择
- 需要索引(比如显示“第几个学生”)→ 用普通 for 循环。
- 需要修改数组元素 → 用普通 for 循环,通过索引修改。
- 只读取值,不需要索引 → 用增强 for 循环,更简洁。
六、数组的常见操作
数组操作是编程中最频繁的操作之一。以下是几个最常用的模式:
6.1 数组求和与平均值
public class ArraySum {
public static void main(String[] args) {
int[] scores = {85, 92, 78, 95, 88};
int total = 0;
for (int score : scores) {
total += score; // total = total + score
}
double average = (double) total / scores.length; // 转成 double 保留小数
System.out.println("总分:" + total);
System.out.println("平均分:" + average);
}
}
6.2 找最大值和最小值
public class ArrayMaxMin {
public static void main(String[] args) {
int[] scores = {85, 92, 78, 95, 88};
int max = scores[0]; // 假设第一个是最大值
int min = scores[0]; // 假设第一个是最小值
for (int i = 1; i < scores.length; i++) {
if (scores[i] > max) {
max = scores[i]; // 找到更大的,更新最大值
}
if (scores[i] < min) {
min = scores[i]; // 找到更小的,更新最小值
}
}
System.out.println("最高分:" + max); // 95
System.out.println("最低分:" + min); // 78
}
}
6.3 查找指定元素
public class ArraySearch {
public static void main(String[] args) {
int[] scores = {85, 92, 78, 95, 88};
int target = 95;
int foundIndex = -1; // -1 表示没找到
for (int i = 0; i < scores.length; i++) {
if (scores[i] == target) {
foundIndex = i;
break; // 找到了就不继续找了
}
}
if (foundIndex != -1) {
System.out.println("找到 " + target + ",位置在索引 " + foundIndex);
} else {
System.out.println("未找到 " + target);
}
}
}
七、二维数组——数组的数组
二维数组可以理解为一张表格——有行和列。比如一个班级的成绩表,每行是一个学生,每列是一个科目。
7.1 声明和创建二维数组
// 声明并创建:3 行 4 列的二维数组
int[][] matrix = new int[3][4];
// 创建并直接赋值
int[][] grid = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
7.2 访问二维数组元素
用两个索引——第一个是行,第二个是列:
int[][] grid = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
System.out.println(grid[0][0]); // 1 —— 第 0 行第 0 列
System.out.println(grid[1][2]); // 7 —— 第 1 行第 2 列
System.out.println(grid[2][3]); // 12 —— 第 2 行第 3 列
// 获取行数和列数
System.out.println("行数:" + grid.length); // 3
System.out.println("列数:" + grid[0].length); // 4(第 0 行的长度)
7.3 遍历二维数组——嵌套循环
int[][] grid = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 外层循环遍历行
for (int i = 0; i < grid.length; i++) {
// 内层循环遍历这一行的每一列
for (int j = 0; j < grid[i].length; j++) {
System.out.print(grid[i][j] + "\t");
}
System.out.println(); // 每行结束换行
}
输出:
1 2 3 4
5 6 7 8
9 10 11 12
八、综合演示:学生成绩统计
下面这个程序综合运用了数组、循环、条件判断,计算学生成绩的总分、平均分、最高分和等级:
public class ScoreAnalyzer {
public static void main(String[] args) {
// 学生姓名和成绩
String[] names = {"张三", "李四", "王五", "赵六", "孙七"};
int[] scores = {85, 92, 78, 95, 60};
System.out.println("========== 成绩统计 ==========");
// 1. 输出每个学生的成绩和等级
for (int i = 0; i < scores.length; i++) {
String grade;
if (scores[i] >= 90) {
grade = "优秀";
} else if (scores[i] >= 80) {
grade = "良好";
} else if (scores[i] >= 70) {
grade = "中等";
} else if (scores[i] >= 60) {
grade = "及格";
} else {
grade = "不及格";
}
System.out.println(names[i] + ":" + scores[i] + " 分 —— " + grade);
}
// 2. 计算总分和平均分
int total = 0;
for (int score : scores) {
total += score;
}
double average = (double) total / scores.length;
// 3. 找最高分和最低分及其对应的学生
int maxIndex = 0;
int minIndex = 0;
for (int i = 1; i < scores.length; i++) {
if (scores[i] > scores[maxIndex]) {
maxIndex = i;
}
if (scores[i] < scores[minIndex]) {
minIndex = i;
}
}
// 4. 统计各等级人数
int excellentCount = 0; // 优秀人数
int passCount = 0; // 及格及以上人数
for (int score : scores) {
if (score >= 90) excellentCount++;
if (score >= 60) passCount++;
}
System.out.println("-----------------------------");
System.out.println("总分:" + total);
System.out.println("平均分:" + average);
System.out.println("最高分:" + scores[maxIndex] + "(" + names[maxIndex] + ")");
System.out.println("最低分:" + scores[minIndex] + "(" + names[minIndex] + ")");
System.out.println("优秀人数:" + excellentCount);
System.out.println("及格人数:" + passCount + " / " + scores.length);
System.out.println("==============================");
}
}
输出:
========== 成绩统计 ==========
张三:85 分 —— 良好
李四:92 分 —— 优秀
王五:78 分 —— 中等
赵六:95 分 —— 优秀
孙七:60 分 —— 及格
-----------------------------
总分:410
平均分:82.0
最高分:95(赵六)
最低分:60(孙七)
优秀人数:2
及格人数:5 / 5
==============================
代码设计要点:
- 用两个平行的数组
names和scores存储学生姓名和成绩,通过同一个索引关联。 - 找最大值时,不直接存储最大值,而是存储最大值所在的索引——这样既能输出最高分,也能输出对应的学生姓名。
- 多个统计任务(总分、平均分、最高最低分、等级人数)各自独立成一个循环,逻辑清晰。
九、本篇动手练习
练习 1:数组反转
新建 Practice6_1.java。创建一个包含 10 个整数的数组并初始化。写代码把这个数组的元素顺序反转(第一个和最后一个交换,第二个和倒数第二个交换……),输出反转前后的数组。
练习 2:冒泡排序
新建 Practice6_2.java。创建一个无序的整数数组。用冒泡排序算法把数组从小到大排序。冒泡排序的逻辑:相邻元素两两比较,如果前面的比后面的大就交换。重复多轮,直到没有任何交换发生。输出排序前后的数组。
练习 3:矩阵转置
新建 Practice6_3.java。创建一个 3×3 的二维数组。输出原矩阵和转置后的矩阵。转置就是把行变成列、列变成行——matrix[i][j] 变成 matrix[j][i]。
练习 4:统计字母频率
新建 Practice6_4.java。声明一个字符串变量 String text = "hello world";。创建一个长度为 26 的整数数组,统计这段文字中 26 个英文字母各出现了多少次(忽略大小写)。提示:字符可以通过 ch - 'a' 转换成 0-25 的索引。
十、本篇小结
这一篇你学会了 Java 中最重要的数据结构之一——数组:
- 数组是什么:同一类型数据的集合,通过索引(从 0 开始)访问。长度在创建时确定,之后不能改变。
- 声明和创建:
数据类型[] 数组名 = new 数据类型[长度];或者直接用花括号初始化{值1, 值2, ...}。 - 访问元素:通过
数组名[索引]读写。索引从 0 到 length-1。超出范围会报ArrayIndexOutOfBoundsException。 - 获取长度:
数组名.length——这是属性,不是方法,不加括号。 - 遍历数组:普通 for 循环(按索引,可以修改元素)和增强 for 循环(
for (类型 变量 : 数组),简洁但只读)。 - 常见操作:求和、平均值、找最大最小值、查找指定元素。
- 二维数组:
int[][] grid = new int[行数][列数];。用两个索引访问,用嵌套循环遍历。
数组和循环是编程中的黄金搭档——数组存数据,循环处理数据。掌握了这两者,你已经可以解决很多实际的计算和统计问题了。下一篇,我们进入 Java 最核心的编程思想——面向对象编程,学习类和对象。
下一篇预告
下一篇——《面向对象(上)——类与对象》:什么是类、什么是对象、怎样定义一个类、怎样创建对象、成员变量和成员方法、构造方法。this 关键字的作用。这是 Java 编程思想的核心,也是从“写脚本”到“写程序”的思维转变。
Java 零基础入门,每周更新。












暂无评论内容