Java循环结构全解析
java循环结构
循环结构用于重复执行一段相同或相似的代码,直到满足某个特定的条件才停止执行。它是简化代码、处理批量任务不可或缺的工具。
Java中主要的循环结构有:for
循环、while
循环 和 do...while
循环。
一、for 循环
for
循环是最常用、结构最清晰的循环,特别适用于循环次数明确的场景。
1. 基本语法与执行流程
-
语法:
java
for (初始化语句; 循环条件; 迭代语句) {// 循环体:要重复执行的代码 }
-
执行流程(非常重要):
- 执行初始化语句(只在循环开始时执行一次)。
- 判断循环条件:
- 如果为
true
,则执行循环体。 - 如果为
false
,则循环结束。
- 如果为
- 执行循环体。
- 执行迭代语句(通常用于改变循环变量)。
- 重复步骤 2、3、4,直到条件为
false
。
-
示例:打印 5 次 “Hello, World!”
java
for (int i = 0; i < 5; i++) {System.out.println("Hello, World! - " + i); }
-
int i = 0;
:初始化一个循环计数器i
,并从 0 开始。 -
i < 5;
:循环条件。只要i
小于 5,循环就继续。 -
i++
:迭代语句。每次循环结束后,i
的值增加 1。 -
输出结果:
text
Hello, World! - 0 Hello, World! - 1 Hello, World! - 2 Hello, World! - 3 Hello, World! - 4
-
2. 特殊用法
-
死循环:如果循环条件永远为
true
,则循环会无限执行下去。java
for (;;) { // 初始化、条件、迭代都可以省略,但分号不能省System.out.println("这是一个死循环");// 实际开发中,通常会用break来在某种条件下跳出这种循环 }
-
多个变量:初始化语句和迭代语句可以包含多条语句,用逗号
,
分隔。java
for (int i = 0, j = 10; i < j; i++, j--) {System.out.println("i=" + i + ", j=" + j); }
二、while 循环
while
循环适用于循环次数不明确,但循环条件明确的场景。它的逻辑是:“当…时,就一直做…”。
1. 基本语法与执行流程
-
语法:
java
while (循环条件) {// 循环体 }
-
执行流程:
- 判断循环条件。
- 如果条件为
true
,则执行循环体;如果为false
,则结束循环。 - 执行完循环体后,再次回到步骤 1。
-
示例 1:模拟用户输入,直到输入 “quit” 为止
java
Scanner scanner = new Scanner(System.in); String input = ""; while (!input.equals("quit")) { // 只要输入的不是"quit",循环就继续System.out.print("请输入指令:");input = scanner.nextLine();System.out.println("你输入了: " + input); } scanner.close();
-
示例 2:计算 1 到 100 的和
java
int sum = 0; int num = 1; while (num <= 100) {sum += num;num++; } System.out.println("1-100的和是:" + sum);
三、do…while 循环
do...while
循环是 while
循环的变体。它先执行一次循环体,然后再判断条件。因此,循环体至少会被执行一次。
1. 基本语法与执行流程
-
语法:
java
do {// 循环体 } while (循环条件); // 注意这里的分号!
-
执行流程:
- 先执行一次循环体。
- 然后判断循环条件。
- 如果条件为
true
,则回到步骤 1;如果为false
,则结束循环。
-
示例:菜单选择,至少显示一次
java
Scanner scanner = new Scanner(System.in); int choice; do {System.out.println("----- 菜单 -----");System.out.println("1. 开始游戏");System.out.println("2. 加载存档");System.out.println("3. 退出");System.out.print("请选择:");choice = scanner.nextInt(); } while (choice < 1 || choice > 3); // 如果输入的不是1,2,3,就循环提示System.out.println("你选择了: " + choice); // ... 根据choice执行后续操作 scanner.close();
四、循环控制语句
循环控制语句可以改变循环的正常执行流程。
控制语句 | 作用 | 适用循环 |
---|---|---|
break | 跳出循环,终止整个循环结构的执行,继续执行循环后面的代码。 | for , while , do...while , switch |
continue | 跳过本次循环,立即开始下一次循环(继续执行迭代语句和条件判断)。 | for , while , do...while |
return | 跳出所在的方法,循环和它后面的代码都不会再执行。 | 任何结构 |
-
break
示例:在数组中查找数字,找到后立即终止循环,提高效率。java
int[] numbers = {10, 20, 30, 40, 50}; int target = 30; boolean found = false;for (int num : numbers) {if (num == target) {found = true;break; // 找到后立即跳出循环,不再检查后面的元素} } System.out.println("找到了吗? " + found);
-
continue
示例:打印 1-10 之间的所有奇数。java
for (int i = 1; i <= 10; i++) {if (i % 2 == 0) { // 如果是偶数continue; // 跳过本次循环的剩余语句,直接执行i++,然后进入下一次循环}System.out.println(i); }
五、增强 for 循环 (for-each Loop)
这是 JDK 5 引入的一种简化语法,专门用于遍历数组和集合(如 ArrayList
)中的所有元素。它避免了操作索引的麻烦,更简洁,不易出错。
-
语法:
java
for (元素类型 局部变量 : 数组或集合对象) {// 使用局部变量即可访问当前元素 }
-
示例:遍历数组和集合
java
// 遍历数组 int[] numbers = {1, 2, 3, 4, 5}; for (int num : numbers) {System.out.println(num); }// 遍历集合(例如ArrayList) ArrayList<String> list = new ArrayList<>(); list.add("Apple"); list.add("Banana"); list.add("Orange"); for (String fruit : list) {System.out.println(fruit); }
-
注意:增强 for 循环是只读的,你不能用它来修改原数组或集合中的元素(对于基本数据类型)或重新赋值(对于引用数据类型)。
六、嵌套循环
一个循环体内又可以包含另一个完整的循环结构,称为嵌套循环。
-
示例:打印九九乘法表
java
for (int i = 1; i <= 9; i++) { // 外层循环控制行for (int j = 1; j <= i; j++) { // 内层循环控制列System.out.print(j + "×" + i + "=" + (i * j) + "\t");}System.out.println(); // 换行 }
七、循环结构的选择:for vs. while vs. do-while
循环类型 | 特点 | 适用场景 |
---|---|---|
for | 循环次数明确。结构紧凑,初始化、条件、迭代都写在一起,一目了然。 | 遍历数组、执行固定次数的任务(如打印10次) |
while | 循环次数不明确,但条件明确。“当…时,就循环”。可能一次都不执行。 | 读取文件直到末尾、等待用户输入特定指令、游戏主循环 |
do-while | 循环次数不明确,但条件明确,且循环体至少需执行一次。“先做,再看条件”。 | 菜单显示、密码验证(至少要让用户输入一次) |
一、核心概念:数据的集装箱
想象一下现实中的集装箱:
- 固定大小:一个集装箱在制造出来时,它的容量就固定了。
- 存放同类物品:一个集装箱通常只存放一类物品,比如全是电视,或全是水果。
- 每个位置有编号:每个集装箱位都有一个唯一的编号(如A01,B02),方便快速定位和存取货物。
Java中的一维数组就是这个概念的数字体现:
- 固定长度:数组一旦被创建,其长度就不可改变。
- 相同数据类型:数组中的所有元素必须是相同的数据类型(如全是
int
,或全是String
)。 - 索引访问:每个元素都有一个从
0
开始的数字索引,通过索引可以快速访问或修改任何位置的元素。
二、数组的声明与初始化
数组的使用分为三个步骤:声明、初始化、赋值/访问。
1. 声明数组
声明数组主要是告诉编译器数组的名称和它将存储的元素类型。
-
语法:
java
// 首选方式 数据类型[] 数组名; // 另一种方式(来源于C/C++,Java中允许但不推荐,可读性较差) 数据类型 数组名[];
-
示例:
java
int[] numbers; // 声明一个整型数组,名为numbers String[] names; // 声明一个字符串数组,名为names double scores[]; // 不推荐的方式
注意:此时仅仅是声明了一个数组变量(引用),它还没有指向任何实际的内存空间,其值为
null
。无法使用,否则会报NullPointerException
。
2. 初始化数组
初始化是为数组分配内存空间的过程。Java中主要有两种初始化方式:
-
静态初始化:在声明数组的同时,直接指定元素内容。
java
// 语法:数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, ..., 元素n}; // 简写语法(只能在声明时使用):数据类型[] 数组名 = {元素1, 元素2, ..., 元素n};int[] numbers = new int[]{1, 2, 3, 4, 5}; String[] weekdays = {"Mon", "Tue", "Wed", "Thu", "Fri"}; // 简写方式
-
动态初始化:在声明数组时,只指定数组的长度,系统会为每个元素分配默认值。
java
// 语法:数据类型[] 数组名 = new 数据类型[数组长度];int[] numbers = new int[5]; // 创建一个长度为5的int数组,默认值全是0 boolean[] flags = new boolean[3]; // 创建一个长度为3的boolean数组,默认值全是false String[] names = new String[4]; // 创建一个长度为4的String数组,默认值全是null
数组元素的默认值:
数据类型 默认值 byte
,short
,int
0
long
0L
float
0.0F
double
0.0
char
'\u0000'
(空字符)boolean
false
引用类型 null
三、数组的访问与操作
1. 访问元素:使用索引
数组元素通过索引来访问。索引是从 0
开始,到 数组长度 - 1
结束的整数。
-
语法:
数组名[索引]
-
示例:
java
int[] numbers = {10, 20, 30, 40};// 获取元素 int firstElement = numbers[0]; // 获取第一个元素:10 int thirdElement = numbers[2]; // 获取第三个元素:30// 修改元素 numbers[1] = 200; // 将第二个元素从20改为200 System.out.println(numbers[1]); // 输出:200
2. 获取数组长度
使用数组对象的 length
属性(注意:不是方法,后面没有()
)来获取数组的长度。
-
语法:
数组名.length
-
示例:遍历数组(这是数组最常用的操作)
java
int[] numbers = {10, 20, 30, 40, 50};// 使用for循环遍历 for (int i = 0; i < numbers.length; i++) { // 条件 i < numbers.length 是关键!System.out.println("Element at index " + i + ": " + numbers[i]); }// 使用增强for循环(for-each)遍历(JDK5+) for (int num : numbers) {System.out.println("Element: " + num); }
注意:
for-each
循环更简洁,但只能用于读取元素,不能用于修改原数组(对于基本类型)或获取当前元素的索引。
四、内存原理与常见异常
1. 内存模型(重要理解)
java
int[] arr; // 栈内存中声明一个引用变量arr,值为null
arr = new int[3]; // 在堆内存中开辟一块连续空间,存放3个int,并赋默认值0。// 然后将这块内存空间的地址赋值给引用变量arr。
arr[0] = 10; // 通过地址找到堆内存中的数组,修改第一个位置的值为10。
关键点:数组是引用数据类型。变量 arr
存储的是数组对象在堆内存中的地址,而不是数据本身。
2. 常见异常
-
空指针异常 (NullPointerException):
当数组变量仅为声明(null
)而未初始化(new
)时,尝试访问其长度或元素会抛出此异常。java
int[] arr = null; System.out.println(arr[0]); // 运行时抛出 NullPointerException System.out.println(arr.length); // 运行时抛出 NullPointerException
-
数组索引越界异常 (ArrayIndexOutOfBoundsException):
当尝试访问不存在的索引(即索引 < 0 或索引 >= 数组长度)时抛出。java
int[] arr = {1, 2, 3}; System.out.println(arr[3]); // 最大有效索引是2,访问3会越界 System.out.println(arr[-1]); // 索引为负数,越界
牢记:数组的有效索引范围永远是
[0, array.length - 1]
。
五、数组的常用操作与案例
1. 求最值
java
int[] numbers = {12, 45, 7, 89, 3, 56};
int max = numbers[0]; // 假设第一个元素是最大值
for (int i = 1; i < numbers.length; i++) {if (numbers[i] > max) {max = numbers[i];}
}
System.out.println("最大值是: " + max);
2. 元素求和/平均值
java
int sum = 0;
for (int num : numbers) {sum += num;
}
double average = (double) sum / numbers.length;
System.out.println("总和: " + sum + ", 平均值: " + average);
3. 数组反转
java
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {// 交换首尾对称位置的元素int temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}
// 反转后arr变为:{5, 4, 3, 2, 1}
二维数组本质上就是一维数组的数组。它可以将数据组织成行和列的表格形式,非常适合表示矩阵、棋盘、地图等结构化数据。
一、核心概念:数组的数组
想象一下现实中的公寓楼或Excel表格:
- 一栋公寓楼有多个楼层(行),每个楼层又有多个房间(列)。
- 一个Excel表格有多个行,每个行又有多个单元格(列)。
Java中的二维数组就是这个概念的数字体现:
- 一个二维数组变量指向一个一维数组,这个一维数组中的每个元素又是一个一维数组。
- 第一个维度通常代表行,第二个维度代表列。
二、二维数组的声明与初始化
和一维数组一样,二维数组的使用也分为声明、初始化、赋值/访问。
1. 声明二维数组
声明主要是告诉编译器数组的名称和它将存储的元素类型。
-
语法:
java
// 首选方式 数据类型[][] 数组名;// 另一种方式(允许但不推荐) 数据类型 数组名[][]; 数据类型[] 数组名[];
-
示例:
java
int[][] matrix; // 声明一个整型的二维数组 String[][] table; // 声明一个字符串的二维数组 double[][] scores; // 声明一个双精度的二维数组
注意:此时数组变量还未初始化,值为
null
。
2. 初始化二维数组
同样分为静态初始化和动态初始化。
-
静态初始化:直接指定所有元素的值。
java
// 语法:数据类型[][] 数组名 = new 数据类型[][]{{元素...}, {元素...}, ...}; // 简写语法:数据类型[][] 数组名 = {{元素...}, {元素...}, ...};int[][] matrix = new int[][]{{1, 2, 3},{4, 5, 6},{7, 8, 9} };// 简写方式(更常用) String[][] names = {{"Mr.", "Mrs.", "Ms."},{"Smith", "Jones", "Lee"} };
-
动态初始化:只指定数组的大小(行数和列数),系统会为每个元素分配默认值。
java
// 方式一:直接指定行数和列数 // 语法:数据类型[][] 数组名 = new 数据类型[行数][列数]; int[][] matrix = new int[3][4]; // 创建一个3行4列的矩阵,所有元素默认值为0// 方式二:先指定行数,再分别为每一行指定列数(创建不规则数组) // 语法:数据类型[][] 数组名 = new 数据类型[行数][]; char[][] pyramid = new char[5][]; // 创建一个有5行的二维数组,但每行的列数还未定pyramid[0] = new char[1]; // 第0行有1列 pyramid[1] = new char[2]; // 第1行有2列 pyramid[2] = new char[3]; // 第2行有3列 pyramid[3] = new char[4]; // 第3行有4列 pyramid[4] = new char[5]; // 第4行有5列 // 这样就创建了一个金字塔形的"不规则数组"
三、二维数组的访问与操作
1. 访问元素:使用行列索引
通过两个索引来访问元素:[行索引][列索引]
。两个索引都从 0
开始。
-
示例:
java
int[][] matrix = {{10, 20, 30},{40, 50, 60} };// 获取元素 int element = matrix[0][1]; // 获取第0行第1列的元素:20 System.out.println(element);// 修改元素 matrix[1][2] = 600; // 将第1行第2列的元素从60改为600
2. 获取数组的长度
二维数组有两个重要的长度属性:
数组名.length
:获取行数(即外层一维数组的长度)。数组名[行索引].length
:获取指定行的列数(即内层某个一维数组的长度)。
-
示例:遍历二维数组(使用嵌套循环)
java
int[][] matrix = {{1, 2, 3},{4, 5},{6, 7, 8, 9} // 这是一个不规则数组 };// 标准for循环遍历(可以获取索引) for (int i = 0; i < matrix.length; i++) { // 外层循环控制行for (int j = 0; j < matrix[i].length; j++) { // 内层循环控制当前行的列System.out.print(matrix[i][j] + " ");}System.out.println(); // 换行 }// 增强for循环(for-each)遍历(更简洁,用于只读操作) for (int[] row : matrix) { // 注意:每个row是一个一维数组for (int element : row) {System.out.print(element + " ");}System.out.println(); }
输出结果:
text
1 2 3 4 5 6 7 8 9
关键点:在嵌套的标准
for
循环中,内层循环的条件必须是j < matrix[i].length
,而不是j < matrix[0].length
,这样才能正确处理不规则数组。
四、内存原理
理解二维数组的内存模型对于深入掌握Java至关重要。
java
int[][] arr = new int[2][3];
- 在栈内存中创建引用变量
arr
。 new int[2][3]
在堆内存中开辟空间:- 首先创建一个长度为2的外层数组,其元素类型是
int[]
(引用类型)。每个元素的默认值是null
。 - 然后为外层数组的每个元素(即每一行)再分别创建一个长度为3的内层数组,其元素类型是
int
。每个内层数组的元素默认值是0
。 - 最后将内层数组的内存地址赋给外层数组对应的元素。
- 首先创建一个长度为2的外层数组,其元素类型是
不规则数组的内存分配:
java
int[][] irregularArr = new int[3][]; // 只创建了外层数组,元素全是null
irregularArr[0] = new int[2]; // 为第0行创建长度为2的内层数组
irregularArr[1] = new int[3]; // 为第1行创建长度为3的内层数组
irregularArr[2] = new int[1]; // 为第2行创建长度为1的内层数组
五、常见应用案例
1. 矩阵转置
将矩阵的行列互换。
java
int[][] original = {{1, 2, 3},{4, 5, 6}
};
int rows = original.length;
int cols = original[0].length;int[][] transposed = new int[cols][rows]; // 新矩阵的行数=原矩阵列数,列数=原矩阵行数for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {transposed[j][i] = original[i][j]; // 行列索引互换}
}
// 转置后transposed为:
// { {1, 4},
// {2, 5},
// {3, 6} }
2. 杨辉三角(帕斯卡三角)
java
java方法
方法是Java中组织代码和实现代码复用的核心机制。它也被称为函数。你可以将它理解为一种“技能”或“工具”,一旦定义好,就可以在需要时反复使用,而无需重复编写相同的代码。
一、核心概念:封装与复用
想象一下现实生活中的场景:
- 你有一台榨汁机。你不需要每次都重新发明如何榨汁,只需要把水果放进去(输入),按下开关,它就会给你果汁(输出)。榨汁的具体过程(电机转动、刀片切割)被封装在了机器内部。
Java中的方法就是这个概念的体现:
- 封装:将一段完成特定功能的代码块
{}
包裹起来,形成一个独立的单元。 - 复用:定义一次,可以在程序的多个地方多次调用。
- 简化代码:使程序结构更清晰、层次更分明,便于阅读和维护。
二、方法的定义与语法
一个方法的标准定义包括以下几个部分:
java
[修饰符] 返回值类型 方法名([参数类型1 参数名1, 参数类型2 参数名2, ...]) {// 方法体:实现具体功能的代码[return 返回值;] // 如果返回值类型不是void,则必须使用return语句
}
让我们来详细拆解每个部分:
1. 方法名
- 方法的名称,遵循小驼峰命名法(如
calculateSum
,getUserName
)。 - 应做到见名知意,通过名字就能大致猜出方法的功能。
2. 修饰符 (Modifier)
- 定义方法的访问权限和特性。目前最常用的是:
public
:公开的,任何其他类都可以访问。static
:静态的,属于类本身,而非类的实例。main
方法必须是static
的。
3. 返回值类型 (Return Type)
- 方法执行后返回给调用者的数据的类型(如
int
,String
,void
)。 - 如果方法不返回任何值,必须使用关键字
void
。
4. 参数列表 (Parameters)
- 方法执行所需要的输入信息,写在
()
内。 - 格式:
(类型1 参数名1, 类型2 参数名2, ...)
- 参数就像方法的“原材料”。一个方法可以有0个、1个或多个参数。
5. 方法体 (Method Body)
- 由
{}
括起来的代码块,包含了实现方法功能的具体语句。
6. return 语句
- 用于结束方法,并将结果返回给调用者。
- 如果方法的返回值类型是
void
,return
语句可以省略,或者写成return;
(仅用于结束方法,不返回任何值)。 - 如果返回值类型不是
void
,则必须包含return 返回值;
语句,且返回值的类型必须与声明的返回值类型兼容。
三、方法的分类与示例
根据是否有参数和返回值,方法可以分为四类:
1. 无参无返回值方法
java
// 定义:打印一条分隔线
public static void printLine() {System.out.println("------------------------");
}// 调用
printLine(); // 输出:------------------------
2. 有参无返回值方法
java
// 定义:打印指定次数的Hello
public static void printHello(int count) { // int count 是形式参数for (int i = 0; i < count; i++) {System.out.println("Hello");}
}// 调用
printHello(3); // 这里的 3 是实际参数
// 输出:
// Hello
// Hello
// Hello
3. 无参有返回值方法
java
// 定义:获取一个简单的问候语
public static String getGreeting() {return "Welcome to Java!"; // 返回一个String类型的值
}// 调用
String message = getGreeting(); // 用变量接收返回值
System.out.println(message); // 输出:Welcome to Java!
4. 有参有返回值方法(最常用)
java
// 定义:计算两个整数的和
public static int add(int a, int b) { // 两个形式参数int sum = a + b;return sum; // 返回计算结果
}// 调用
int result = add(5, 3); // 传递两个实际参数
System.out.println("5 + 3 = " + result); // 输出:5 + 3 = 8
// 也可以直接使用方法的返回值
System.out.println("10 + 20 = " + add(10, 20)); // 输出:10 + 20 = 30
四、方法的调用与执行流程
调用方法:在另一个方法(如 main
方法)中,通过 方法名(参数);
的方式来执行它。
执行流程(非常重要):
- 程序从
main
方法开始执行。 - 当遇到方法调用时(如
add(5, 3);
),程序会暂停当前方法的执行。 - 程序会跳转到被调用方法(
add
)的内部开始执行。 - 参数传递:将实参的值(
5
和3
)拷贝一份,传递给形参(a
和b
)。 - 执行被调用方法的方法体。
- 当执行到
return
语句或方法体结束时,被调用方法执行完毕。 - 程序返回到当初暂停的地方(
main
方法中),并继续向下执行。如果有返回值,则用返回值代替方法调用。
示例分析:
java
public class MethodFlow {public static void main(String[] args) {System.out.println("程序开始"); // 1int x = 10; // 2int y = 20; // 3int sum = add(x, y); // 4 -> 跳转到add方法System.out.println("和是: " + sum); // 7System.out.println("程序结束"); // 8}public static int add(int a, int b) { System.out.println("正在计算加法..."); // 5return a + b; // 6 -> 带着结果30返回main方法}
}
输出结果:
text
程序开始
正在计算加法...
和是: 30
程序结束
五、方法的重载 (Overload)
这是Java非常重要的一个特性。
- 概念:在同一个类中,允许存在多个同名的方法,只要它们的参数列表不同即可。
- 参数列表不同指的是:参数个数不同、参数类型不同、或参数顺序不同。
- 注意:返回值类型不同不足以构成重载。
- 优点:解决了功能相似的方法,因参数不同而需要起不同名字的麻烦,提高了方法的易用性。
重载示例:
java
public class Calculator {// 计算两个int数的和public static int add(int a, int b) {return a + b;}// 重载:计算三个int数的和 (参数个数不同)public static int add(int a, int b, int c) {return a + b + c;}// 重载:计算两个double数的和 (参数类型不同)public static double add(double a, double b) {return a + b;}// 重载:参数顺序不同 (但这种情况在实际开发中很少见,容易混淆)public static void printInfo(String name, int age) {System.out.println("Name: " + name + ", Age: " + age);}public static void printInfo(int age, String name) {System.out.println("Age: " + age + ", Name: " + name);}// 错误示例:仅返回值类型不同,不是重载,会编译报错// public static double add(int a, int b) {// return (double)(a + b);// }
}// 调用
System.out.println(Calculator.add(1, 2)); // 调用add(int, int)
System.out.println(Calculator.add(1, 2, 3)); // 调用add(int, int, int)
System.out.println(Calculator.add(1.5, 2.5)); // 调用add(double, double)
JVM在调用方法时,会根据你传入的实际参数的类型和数量,自动匹配最合适的一个重载方法。
六、方法的参数传递机制:值传递
这是Java方法的一个核心且易错的特性。
- 核心规则:Java中方法的参数传递,永远是值传递。即将实际参数值的副本传入方法内部,而参数本身不会受到影响。
- 对于基本数据类型(如
int
,double
,char
),传递的是值的拷贝。在方法内修改形参,不会影响实参。 - 对于引用数据类型(如数组、对象),传递的是地址的拷贝。在方法内通过这个地址修改对象的内容(如修改数组元素、调用对象的方法),会影响实参所指向的原始对象。但如果让形参指向一个新的对象,则不会影响实参。
示例1:基本数据类型(值不受影响)
java
public static void main(String[] args) {int num = 10;changeValue(num); // 传递的是10这个值的拷贝System.out.println("main方法中的num: " + num); // 输出:10 (原值未变)
}public static void changeValue(int value) { // value是num的一个副本value = 100; // 修改的是副本的值System.out.println("changeValue方法中的value: " + value); // 输出:100
}
示例2:引用数据类型(内容受影响)
java
public static void main(String[] args) {int[] arr = {1, 2, 3};changeArray(arr); // 传递的是数组arr的地址拷贝System.out.println("main方法中的arr[0]: " + arr[0]); // 输出:100 (内容被改变了!)
}public static void changeArray(int[] array) { // array和arr指向同一个数组对象array[0] = 100; // 通过地址修改了堆内存中数组对象的内容
}
七、变量的作用域
在方法中定义的变量称为局部变量。
- 作用域:局部变量只在定义它的代码块
{}
内有效。 - 生命周期:当方法被调用时,Java虚拟机会为其局部变量分配内存;当方法调用结束,这些局部变量所占用的内存会被自动释放。
- 重要规则:在重叠的作用域内(如嵌套的
{}
),不能定义同名的局部变量。