Java 是值传递还是引用传递? 冷不防 2024-04-03 07:30 26阅读 0赞 先来曝答案,**在 Java 语言中,本质只有值传递,而无引用传递**,解释和证明详见正文。 说到值传递和引用传递我们不得不提到两个概念:值类型和引用类型。 #### 1.值类型 #### 通俗意义上来说,所谓的值类型指的就是 Java 中的 8 大基础数据类型: * 整数型:byte、int、short、long * 浮点型:float、double * 字符类型:char * 布尔类型:boolean * ![027492d636d52ba75f3ee76143fa948b.png][] **从 JVM 层面来讲:所谓的值类型指的是在赋值时,直接在栈中(Java 虚拟机栈)生成值的类型**,如下图所示: ![fb0530577ebff7d8b37e12f5dbee16e0.png][] #### 2.引用类型 #### 引用类型是指除值类型之外的数据类型,比如: * 类 * 接口 * 数组 * 字符串 * 包装类(Integer、Double...) ![4b3c1c70d425cec156ec3fbc06fa6a72.png][] **从 JVM 的层面来讲,所谓的引用类型是指,在初始化时将引用生成栈上,而值生成在堆上的这些数据类型**,如下图所示: ![1519cd1339c9edbec2d8b4fab6b87737.png][] #### 3.值传递 #### **值传递(Pass By Value)指的是方法传参时,传递的是原内容的副本,因此对副本进行如何修改都不会影响原内容。** 实现代码如下: public class PassTest { public static void main(String[] args) { int age = 18; System.out.println("调用方法前:" + age); intTest(age); System.out.println("调用方法后:" + age); } private static void intTest(int age) { age = 30; System.out.println("方法中修改为:" + age); } } 程序的执行结果为: > 调用方法前:18 > > 方法中修改为:30 > > 调用方法后:18 从上述结果可以看出,在方法中修改参数并未影响原内容,我们把这种传参方式称之为值传递。 #### 4.引用传递 #### **引用传递(Pass By Reference)指的是方法传参时,传递的是参数本身,因此对参数进行任意修改都会影响原内容。** 模拟“引用传递”的实现代码如下: public class PassTest { public static void main(String[] args) { char[] name = {'张', '哥'}; System.out.println("调用方法前:" + new String(name)); paramTest(name); System.out.println("调用方法后:" + new String(name)); } private static void paramTest(char[] n) { n[1] = '神'; System.out.println("方法中修改为:" + new String(n)); } } 程序的执行结果为: > 调用方法前:张哥 > > 方法中修改为:张神 > > 调用方法后:张神 从上述的结果可以看出在 `paramTest` 方法中修改了参数之后,在 `main` 方法中再打印参数时,发现参数的值也跟着发生了改变,那么似乎我们可以得出结论,Java 中貌似也有“引用传递”,然而实事并如此,我们接着看。 #### 5.真假“引用传递” #### 我们给上面的代码添加一行,如下所示: public class PassByValue { public static void main(String[] args) { char[] name = {'张', '哥'}; System.out.println("调用方法前:" + new String(name)); paramTest(name); System.out.println("调用方法后:" + new String(name)); } private static void paramTest(char[] n) { n = new char[2]; // 添加此行代码 n[1] = '神'; System.out.println("方法中修改为:" + new String(n)); } } 程序的执行结果为: > 调用方法前:张哥 > > 方法中修改为:神 > > 调用方法后:张哥 从上述结果可以看出,当我们在 `paramTest` 方法中添加 `new char[]` 之后,“引用传递”就突然变值传递了?为什么? 这是因为,**在 Java 语言中本质上只有值传递,也就说 Java 的传参只会传递它的副本,并不会传递参数本身。** 前面那个带引号的“引用传递”其实只是传递了它的引用副本,如下图所示: ![5c646db381c678eaed3b6cf6025ff144.png][] > > PS:《Java虚拟机规范》中对 Java 堆的描述是:“所有的对象实例以及**数组**都应当在堆上分配”。 所以**我们在调用 `new char[]` 之后,可以看出 `n` 对象有了新地址,而原内容并未被修改,如果按照引用传递的思路来看的话,不管执行任何方式的修改都会改变原内容,因此我们可以更加确认 Java 语言中只有值传递**,如下图所示: ![1c6bdbafe5755836bc7492813d085eda.png][] #### 总结 #### 通过本文的内容,我们可以得出:**在 Java 语言中只有值传递,方法传参时只会传递副本信息而非原内容**。我们还知道了基础数据类型会直接生成到栈上,而对象或数组则会在栈和堆上都生成信息,并将栈上生成的引用,直接指向堆中生成的数据,如下图所示: ![d84bfa924c38601990869fc036f41ca3.png][] [027492d636d52ba75f3ee76143fa948b.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/03/4748a0cd6ce14729bef3f496847d3890.png [fb0530577ebff7d8b37e12f5dbee16e0.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/03/269d24cfab2040bcaa5fb77ddbc17453.png [4b3c1c70d425cec156ec3fbc06fa6a72.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/03/91f434b3a8f8410384d920282c3bb055.png [1519cd1339c9edbec2d8b4fab6b87737.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/03/0352b365badd442a825c0bdfe73dcea3.png [5c646db381c678eaed3b6cf6025ff144.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/03/988264f8f8c742c0ab3511df966064b1.png [1c6bdbafe5755836bc7492813d085eda.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/03/06fc99ce1fc6458d889f2dc1e255a968.png [d84bfa924c38601990869fc036f41ca3.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/03/7598ac6387c3456b8c0e7d61d69cbba3.png
还没有评论,来说两句吧...