第三章 下 Java数组与函数:高效编程双利器
1 数组
当程序中需要存储大量同类型的数据时,需要使用“数组”。例如,为了保存50个学生的语文考试成绩,如果没有数组,则需要定义50个变量才能保存50个学生的成绩,这非常不方便,而如果使用数组,则只需要定义一个数组变量即可。
1.1 定义数组
在Java中,定义数组需要两个步骤:第一步,定义数组变量的名称和数据类型;第二步,确定数组的元素个数。定义数组变量的名称和数据类型的一般形式是:
数据类型[] 数组变量名;
这里仅仅完成了第一步,也就是只定义了数组的数据类型和变量名,并没有说明这个数组包含多少个元素。为了说明数组的元素个数,需要使用Java的"new"关键字为数组创建存储空间。确定数组元素个数的一般形式是:
数组变量名 = new 数据类型[元素个数];
在使用"new"关键字创建数组时,Java会自动将每个数组元素的值初始化为对应数据类型的默认值(数值类型为0,布尔类型为false,引用类型为null)。
例如,为了定义一个能够保存50个学生语文成绩的数组变量,可以使用如下语句:
float[] scores;
scores = new float[50];
在Java中,也可以将定义数组的两个步骤合并为一个步骤,如下所示:
数据类型[] 数组变量名 = new 数据类型[元素个数];
类似的,为了定义一个能够保存50个学生语文成绩的数组变量,可以使用如下语句:
float[] scores = new float[50];
还可以在定义数组时同时完成对数组元素的初始化:
数据类型[] 数组变量名 = new 数据类型[] {初始值0, 初始值1, ..., 初始值k};
或者使用简化形式:
数据类型[] 数组变量名 = {初始值0, 初始值1, ..., 初始值k};
采用这种方式定义并初始化数组时,大括号里面的元素个数就是数组的元素个数。
示例:
// 方式1:先声明后分配空间 int[] numbers1; numbers1 = new int[5]; // 方式2:声明同时分配空间 int[] numbers2 = new int[5]; // 方式3:声明同时初始化 int[] numbers3 = new int[] {1, 2, 3, 4, 5}; // 方式4:简化初始化 int[] numbers4 = {1, 2, 3, 4, 5}; // 字符串数组示例 String[] names = {"张三", "李四", "王五"}; // 布尔数组示例 boolean[] flags = new boolean[3]; // 默认值都是false1.2 访问数组元素
一旦定义了数组并通过“new”关键字确定了数组的元素个数,就可以使用“[下标]”运算符访问数组的元素,其中“下标”是一个整数值:假定数组的元素个数为N,那么,“下标”取值范围从0、1、2 ...到N-1。
public static void main(String[] args) { float[] salary = new float[12]; salary[0] = 5000.15F; salary[1] = 6060.6F; System.out.println("一月份的收入是:" + salary[0]); System.out.println("二月份的收入是:" + salary[1]); System.out.println("三月份的收入是:" + salary[2]); System.out.println("十二月份的收入是:" + salary[11]); }1.3 使用for each遍历数组元素
使用数组类似于定义了多个同名同类型的变量,数组的这一特性非常适合用于对数组的遍历:访问数组中的每一个元素。当然,为了遍历数组中的元素,可以使用前面介绍的for循环或者while循环。
public static void main(String[] args) { float[] salary = {5000.0F, 1234.5F, 6090.5F, 8000F, 6781.5F, 6712.8F, 2312.4F, 3456.7F, 10000.5F, 2111.8F, 4070F, 8760.5F}; float total = 0; for(int i=0; i<12; i++) { total += salary[i]; } System.out.println("全年的收入是:" + total); }While循环可以完成相同的任务;
在Java中,为了遍历数组元素,还可以使用一种更为简单的方式:使用for each循环,如下面的例子所示:
public static void main(String[] args) { float[] salary = {5000.0F, 1234.5F, 6090.5F, 8000F, 6781.5F, 6712.8F, 2312.4F, 3456.7F, 10000.5F, 2111.8F, 4070F, 8760.5F}; float total = 0; for(float m : salary) total += m; System.out.println("全年的收入是:" + total); }for each的一般形式如下:
1.4 二维数组
在Java中可以定义一维数组,当然也可以定义二维数组,甚至更高维的数组。二维数组非常类似日常生活中的表格:包括数据行和数据列。
二维数组的定义:
二维数组可以看作是一维数组的数组,即数组的每个元素又是一个一维数组。定义二维数组的语法如下:
// 方式1:先声明后分配空间 int[][] matrix1; matrix1 = new int[3][4]; // 3行4列的二维数组 // 方式2:声明同时分配空间 int[][] matrix2 = new int[3][4]; // 方式3:声明同时初始化 int[][] matrix3 = new int[][] { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // 方式4:简化初始化 int[][] matrix4 = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // 不规则二维数组(每行长度不同) int[][] irregular = new int[3][]; irregular[0] = new int[2]; // 第0行有2个元素 irregular[1] = new int[3]; // 第1行有3个元素 irregular[2] = new int[4]; // 第2行有4个元素访问二维数组元素:
访问二维数组元素需要使用两个下标:第一个下标表示行索引,第二个下标表示列索引。索引从0开始。
public class TwoDArrayExample { public static void main(String[] args) { // 定义一个3x3的二维数组 int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // 访问特定元素 System.out.println("matrix[0][0] = " + matrix[0][0]); // 输出: 1 System.out.println("matrix[1][2] = " + matrix[1][2]); // 输出: 6 // 修改元素值 matrix[2][1] = 88; System.out.println("修改后 matrix[2][1] = " + matrix[2][1]); // 输出: 88 // 遍历二维数组 System.out.println("二维数组所有元素:"); for (int i = 0; i &lt; matrix.length; i++) { for (int j = 0; j &lt; matrix[i].length; j++) { System.out.print(matrix[i][j] + " "); } System.out.println(); } // 使用for-each遍历 System.out.println("使用for-each遍历:"); for (int[] row : matrix) { for (int value : row) { System.out.print(value + " "); } System.out.println(); } } }二维数组的应用场景:
- 表格数据存储:如学生成绩表(行:学生,列:科目)
- 矩阵运算:如矩阵加法、乘法等数学运算
- 游戏棋盘:如棋盘游戏、扫雷等
- 图像处理:像素点可以表示为二维数组
示例:学生成绩表
public class StudentGrades { public static void main(String[] args) { // 3个学生,4门科目 double[][] grades = { {85.5, 90.0, 78.5, 92.0}, // 学生1的成绩 {76.0, 88.5, 91.0, 79.5}, // 学生2的成绩 {92.5, 87.0, 84.5, 95.0} // 学生3的成绩 }; // 计算每个学生的平均分 System.out.println("学生平均分:"); for (int i = 0; i < grades.length; i++) { double sum = 0; for (int j = 0; j < grades[i].length; j++) { sum += grades[i][j]; } double average = sum / grades[i].length; System.out.printf("学生%d的平均分: %.2f%n", i + 1, average); } // 计算每门科目的平均分 System.out.println("\n科目平均分:"); for (int j = 0; j &lt; grades[0].length; j++) { double sum = 0; for (int i = 0; i &lt; grades.length; i++) { sum += grades[i][j]; } double average = sum / grades.length; System.out.printf("科目%d的平均分: %.2f%n", j + 1, average); } } }2 函数及其调用
当程序功能复杂且代码量比较大时,可以根据业务功能将程序拆分为多个功能部件,称这些功能部件为"函数",也称为"方法"。一个Java类可以包含多个函数。函数是规模化程序设计的有力手段,可以提高代码的可读性、可维护性和复用性。
函数的定义:
函数定义的基本语法:
[访问修饰符] 返回类型 函数名(参数列表) { // 函数体 [return 返回值;] }示例:判断质数的函数
import java.util.Scanner; public class PrimeNumberChecker { /** * 判断一个数是否为质数 * @param number 要判断的整数 * @return 如果是质数返回true,否则返回false */ public static boolean isPrime(int number) { if (number <= 1) { return false; } // 优化:只需要检查到sqrt(number) for (int i = 2; i * i <= number; i++) { if (number % i == 0) { return false; } } return true; } /** 主函数:从键盘接收用户输入,判断是否为质数 */ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int input; System.out.println("质数判断程序(输入0结束)"); while (true) { System.out.print("请输入一个整数:"); input = scanner.nextInt(); if (input == 0) { System.out.println("程序结束。"); break; } if (isPrime(input)) { System.out.println(input + " 是质数。"); } else { System.out.println(input + " 不是质数。"); } } scanner.close(); } }函数调用的优势:
- 代码复用:相同的功能只需编写一次,多处调用
- 模块化:将复杂问题分解为小问题,每个函数解决一个特定问题
- 可维护性:修改功能只需修改一处,不影响其他代码
- 可读性:通过有意义的函数名,代码更易理解
更多函数示例:
public class MathFunctions { // 计算两个数的最大值 public static int max(int a, int b) { return a > b ? a : b; } // 计算阶乘 public static long factorial(int n) { if (n < 0) { throw new IllegalArgumentException("阶乘不能为负数"); } long result = 1; for (int i = 2; i <= n; i++) { result *= i; } return result; } // 计算数组的平均值 public static double average(double[] numbers) { if (numbers == null || numbers.length == 0) { return 0; } double sum = 0; for (double num : numbers) { sum += num; } return sum / numbers.length; } // 打印数组 public static void printArray(int[] array) { System.out.print("["); for (int i = 0; i < array.length; i++) { System.out.print(array[i]); if (i < array.length - 1) { System.out.print(", "); } } System.out.println("]"); } public static void main(String[] args) { // 调用max函数 System.out.println("5和8的最大值是:" + max(5, 8)); // 调用factorial函数 System.out.println("5的阶乘是:" + factorial(5)); // 调用average函数 double[] scores = {85.5, 90.0, 78.5, 92.0}; System.out.println("平均分是:" + average(scores)); // 调用printArray函数 int[] numbers = {1, 2, 3, 4, 5}; printArray(numbers); } }函数参数传递:
- 值传递:基本数据类型(int, double, boolean等)传递的是值的副本
- 引用传递:数组和对象传递的是引用的副本,可以修改原对象内容
public class ParameterPassing { // 基本数据类型 - 值传递 public static void modifyValue(int x) { x = 100; // 修改的是副本,不影响原值 } // 数组 - 引用传递 public static void modifyArray(int[] arr) { if (arr.length > 0) { arr[0] = 999; // 修改会影响原数组 } } public static void main(String[] args) { int num = 10; System.out.println("修改前num = " + num); // 输出: 10 modifyValue(num); System.out.println("修改后num = " + num); // 输出: 10(未改变) int[] numbers = {1, 2, 3}; System.out.println("修改前numbers[0] = " + numbers[0]); // 输出: 1 modifyArray(numbers); System.out.println("修改后numbers[0] = " + numbers[0]); // 输出: 999(已改变) } }3 案例:学生成绩计算系统
全班有20个学生,近期进行了数学课阶段考试,需要编写一个Java程序对成绩进行统计。编写一个程序,首先输入全班的考试成绩,然后计算并输出学生成绩的最高分、最低分和平均分。
要输入和保存20个学生的数学成绩,最好的方式就是定义一个float类型的数组变量,并指定数组的元素个数为20,当然,也需要定义保存最高成绩、最低成绩和平均成绩的变量。之后,使用for循环或者while循环提示输入成绩,在输入成绩的同时计算成绩的最高分、最低分和平均分。
package org.example; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); float[] scores = new float[20]; float max = -10.F, min = 200.0F, avg = 0.0F; for(int i=0; i<20; i++) { System.out.println("请输入第" + i + "个学生的成绩:"); scores[i] = sc.nextFloat(); if (max < scores[i]) max = scores[i]; if (min > scores[i]) min = scores[i]; avg = avg + scores[i]; } avg = avg / 20; System.out.println("最高分:" + max); System.out.println("最低分:" + min); System.out.println("平均分:" + avg); } }4 全文总结
本文系统介绍了Java中数组和函数的核心概念与应用。首先详细讲解了数组的定义、访问、遍历(包括for-each循环)以及二维数组的使用,通过多个代码示例展示了数组在实际编程中的应用。接着深入探讨了函数的定义、调用、参数传递机制及其在代码复用、模块化、可维护性和可读性方面的优势。最后通过"学生成绩计算系统"案例,将数组与函数知识结合,演示了如何解决实际问题。文章内容由浅入深,理论与实践结合,为Java初学者提供了全面的学习指导。