java值传递和引用传递的区别?举例一些常见都笔试面试题说明,最后有速记口诀
先说结论:
Java 里只有值传递,没有真正的引用传递。
很多人会混淆,是因为:
- 基本类型传的是"值的副本"
- 对象传的是"引用的副本"
注意:对象传的是引用的副本,不是引用传递。
1. 值传递和引用传递到底区别是什么
值传递 :把实参的值复制一份给形参。
方法里改形参,不会直接改掉调用者手里的那个变量。
引用传递 :把"变量本身"交给方法。
方法里如果改了这个引用绑定的对象,甚至让它指向别处,调用者也会跟着变。
Java 没有这种"真正的引用传递"。
2. Java 里到底怎么传
基本类型
例如 int、double、char
传的是数值副本。
java
public class Demo {
public static void add(int x) {
x++;
}
public static void main(String[] args) {
int a = 10;
add(a);
System.out.println(a); // 10
}
}
原因:add 里拿到的是 a 的副本 x,改的是 x,不是 a。
引用类型
例如 String、数组、普通对象
传的是"引用的副本"。
java
class Person {
String name;
}
public class Demo {
public static void change(Person p) {
p.name = "Alice";
}
public static void main(String[] args) {
Person p = new Person();
p.name = "Bob";
change(p);
System.out.println(p.name); // Alice
}
}
这里为什么变了?
p里存的是对象地址- 调用方法时,把这个地址复制一份给了形参
- 两个引用都指向同一个对象
- 所以改对象内部状态,外面能看到
但这依然是值传递,因为传过去的是"地址这个值"的副本。
3. 最容易考的面试陷阱
题1:基本类型一定改不动
java
public static void change(int x) {
x = 100;
}
public static void main(String[] args) {
int a = 10;
change(a);
System.out.println(a);
}
结果:10
题2:改对象属性,外面能看到
java
class Student {
int age;
}
public static void change(Student s) {
s.age = 20;
}
public static void main(String[] args) {
Student s = new Student();
s.age = 10;
change(s);
System.out.println(s.age);
}
结果:20
题3:方法里把参数指向新对象,外面不变
java
class Student {
int age;
}
public static void change(Student s) {
s = new Student();
s.age = 20;
}
public static void main(String[] args) {
Student s = new Student();
s.age = 10;
change(s);
System.out.println(s.age);
}
结果:10
原因:
- 方法里只是让"形参副本"指向了新对象
- 外面的
s还指向原来的对象
这题是面试最爱问的。
题4:String 为什么改不掉
java
public static void change(String str) {
str = str + " world";
}
public static void main(String[] args) {
String s = "hello";
change(s);
System.out.println(s);
}
结果:hello
原因有两层:
- Java 还是值传递
String不可变,str + " world"会产生新对象,只改了形参的指向
题5:数组元素能改,但整个数组换掉不行
java
public static void change(int[] arr) {
arr[0] = 99;
}
public static void main(String[] args) {
int[] a = {1, 2, 3};
change(a);
System.out.println(a[0]); // 99
}
能改元素,因为操作的是同一个数组对象。
再看:
java
public static void change(int[] arr) {
arr = new int[]{9, 9, 9};
}
public static void main(String[] args) {
int[] a = {1, 2, 3};
change(a);
System.out.println(a[0]); // 1
}
不能改外面的引用,因为只是改了形参副本。
题6:交换两个值为什么失败
java
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
public static void main(String[] args) {
int x = 1, y = 2;
swap(x, y);
System.out.println(x + ", " + y);
}
结果:1, 2
因为交换的是副本,不是原变量。
这题常引出结论:
Java 不能像 C++ 引用参数那样直接交换调用者的两个基本类型变量。
4. 面试里最标准的一句话
如果面试官问:
"Java 是值传递还是引用传递?"
标准答法:
Java 永远是值传递。对于基本类型,传的是值本身;对于对象类型,传的是对象引用的副本。
5. 一张表记住
| 参数类型 | 传递内容 | 方法内修改是否影响外部变量 | 方法内修改对象内容是否影响外部 |
|---|---|---|---|
| 基本类型 | 值的副本 | 否 | 不适用 |
| 引用类型 | 引用的副本 | 否 | 是 |
6. 面试高频误区
-
"Java 对象是引用传递"
错。是引用的值传递。
-
"方法里
new一个对象,外面也会变"错。只改了形参指向。
-
"String 传进去后改不了,说明不是引用类型"
错。
String是引用类型,只是它不可变。
7. 最后给你一个背诵版
Java 只有值传递。
基本类型传值副本;引用类型传引用副本。
所以:改对象内容能影响外部,改引用指向不能影响外部。
可以直接背这版。
口诀版
Java 只有值传递,绝无引用传递。
基本类型传数值,对象类型传地址副本。
改值不影响外面,改对象内容可能影响外面。
改引用指向没用,new 了对象也带不出去。
String 看着像能改,其实不可变。
数组、对象看同理:改内部可以,换整体不行。
面试答题模板
如果面试官问"Java 到底是值传递还是引用传递",标准回答直接说:
Java 永远是值传递。基本类型传的是值的副本;引用类型传的是引用的副本。
因此,方法内修改对象的成员变量,外部可能看到变化;但让形参重新指向新对象,外部不会变。
高频判断口诀
int、double、char:改形参,外面不变对象.属性 = xxx:外面通常会变形参 = new Xxx():外面不变形参 = 另一个对象:外面不变arr[0] = ...:外面会变arr = new int[]{...}:外面不变str = str + "x":外面不变
笔试速判四字诀
看你改谁
- 改"对象里面的东西":可能影响外面
- 改"形参本身指向":一定不影响外面
最短背诵版
Java 只有值传递。
基本类型传值,对象类型传引用副本。
能改对象内容,不能改外部引用指向。