在Java学习过程中,“值传递”和“引用传递”是一个绕不开的基础重点,也是很多初学者容易混淆的知识点。不少同学会疑惑:为什么修改方法内的基本类型变量,外部变量不受影响?而修改对象类型变量的属性,外部却能感知到?今天我们就结合实际代码,把这两个概念的区别讲透。
首先要明确一个核心前提:Java中只有值传递,不存在引用传递。很多人之所以困惑,是因为对“值”的理解不够准确——这里的“值”,对于基本类型来说是具体的数值,对于引用类型来说则是对象的内存地址。下面我们就通过具体代码案例来拆解分析。
先看一段大家很熟悉的测试代码,通过基本类型(int)和自定义对象(people)的传递,观察方法调用前后变量的变化:

大家可以先思考一下运行结果,再看下面的输出:

从结果能明显看出:调用fun1后,外部的a值还是5,没被方法内的修改影响;而调用fun2后,外部的b.age变成了10,被方法内的修改改变了。这就是两种传递方式的直观差异,下面我们深入分析原因。
对于int、char、boolean等基本数据类型,变量存储的是直接的数值,当把这类变量作为参数传递给方法时,Java会创建一个该数值的“副本”,并把副本传递给方法的形参。
结合案例中的fun1调用过程理解:
对于对象(包括自定义对象、数组、集合等),变量存储的不是对象本身,而是对象在堆内存中的地址(可以理解为“指向对象的指针”)。当把引用类型变量作为参数传递时,Java同样会创建一个“地址副本”,并把副本传递给方法的形参。
结合案例中的fun2调用过程理解:
很多人会把引用类型的传递误认为“引用传递”,核心是混淆了“修改对象属性”和“修改变量指向”的区别。我们可以做一个补充测试:在fun2中尝试修改d的指向(让d指向新的对象),看看外部的b是否会受影响。

可以看到,外部的b.age依然是6,没有被修改。原因很简单:方法内的d = new people(),只是修改了d变量存储的地址(让它指向新的对象),而这个修改的是“地址副本”,和原始变量b存储的地址无关。b依然指向最初创建的那个people对象,所以它的age属性还是6。
这就进一步证明了:Java中引用类型的传递,传递的依然是“值”(地址的副本),而不是引用本身。真正的“引用传递”应该是形参和实参指向同一个变量(而非地址副本),修改形参的指向会直接影响实参,但Java并不支持这种传递方式。
1. 核心原则:Java中所有参数传递都是值传递,传递的是“实参的副本”;
2. 基本类型传递:副本是“具体数值”,方法内修改副本不影响原始变量;
3. 引用类型传递:副本是“对象地址”,方法内通过地址修改对象属性,会影响原始对象(因为指向同一个对象),但修改副本的地址(指向新对象),不影响原始变量的指向;
4. 关键区分:判断影响的核心是“修改的是副本本身,还是副本指向的对象”。
通过上面的案例和分析,相信大家对Java的值传递和引用传递已经有了清晰的认识。其实只要抓住“副本”这个核心,再区分“基本类型副本是数值,引用类型副本是地址”,就能轻松应对所有相关的问题啦。如果还有疑问,欢迎在评论区留言讨论~