• Java 是值传递还是?


    1、值类型

    通俗意义上来说,所谓的值类型指的就是 Java 中的 8 大基础数据类型:

    • 整数型:byte、int、short、long
    • 浮点型:float、double
    • 字符类型:char
    • 布尔类型:boolean

    ​从 JVM 层面来讲:所谓的值类型指的是在赋值时,直接在栈中(Java 虚拟机栈)生成值的类型,如下图所示:

    2、引用类型

    引用类型是指除值类型之外的数据类型,比如:

    • 接口
    • 数组
    • 字符串
    • 包装类(Integer、Double...)

    从 JVM 的层面来讲,所谓的引用类型是指,在初始化时将引用生成栈上,而值生成在堆上的这些数据类型,如下图所示:

    3、值传递

    值传递(Pass By Value)指的是方法传参时,传递的是原内容的副本,因此对副本进行如何修改都不会影响原内容。

    实现代码如下:

    1. class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public class PassTest {
    2. public static void main(String[] args) {
    3. int age = 18;
    4. System.out.println("调用方法前:" + age);
    5. intTest(age);
    6. System.out.println("调用方法后:" + age);
    7. }
    8. private static void intTest(int age) {
    9. age = 30;
    10. System.out.println("方法中修改为:" + age);
    11. }
    12. }
  • 程序的执行结果为:

    调用方法前:18

    方法中修改为:30

    调用方法后:18

    从上述结果可以看出,在方法中修改参数并未影响原内容,我们把这种传参方式称之为值传递。

    4、引用传递

    引用传递(Pass By Reference)指的是方法传参时,传递的是参数本身,因此对参数进行任意修改都会影响原内容。

    模拟“引用传递”的实现代码如下:

    1. class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public class PassTest {
    2. public static void main(String[] args) {
    3. char[] name = {'磊', '哥'};
    4. System.out.println("调用方法前:" + new String(name));
    5. paramTest(name);
    6. System.out.println("调用方法后:" + new String(name));
    7. }
    8. private static void paramTest(char[] n) {
    9. n[1] = '神';
    10. System.out.println("方法中修改为:" + new String(n));
    11. }
    12. }

程序的执行结果为:

调用方法前:磊哥

方法中修改为:磊神

调用方法后:磊神

从上述的结果可以看出在 paramTest 方法中修改了参数之后,在 main 方法中再打印参数时,发现参数的值也跟着发生了改变,那么似乎我们可以得出结论,Java 中貌似也有“引用传递”,然而实事并如此,我们接着看。

5、真假“引用传递”

我们给上面的代码添加一行,如下所示:

  1. class="prettyprint hljs cs" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto;">public class PassByValue {
  2. public static void main(String[] args) {
  3. char[] name = {'磊', '哥'};
  4. System.out.println("调用方法前:" + new String(name));
  5. paramTest(name);
  6. System.out.println("调用方法后:" + new String(name));
  7. }
  8. private static void paramTest(char[] n) {
  9. n = new char[2]; // 添加此行代码
  10. n[1] = '神';
  11. System.out.println("方法中修改为:" + new String(n));
  12. }
  13. }

程序的执行结果为:

调用方法前:磊哥

方法中修改为:神

调用方法后:磊哥

从上述结果可以看出,当我们在 paramTest​ 方法中添加 new char[] 之后,“引用传递”就突然变值传递了?为什么?

这是因为,在 Java 语言中本质上只有值传递,也就说 Java 的传参只会传递它的副本,并不会传递参数本身。​

前面那个带引号的“引用传递”其实只是传递了它的引用副本,如下图所示:

PS:《Java虚拟机规范》中对 Java 堆的描述是:“所有的对象实例以及 数组 都应当在堆上分配”。

所以我们在调用 new char[]​ 之后,可以看出 ​n​ 对象有了新地址,而原内容并未被修改,如果按照引用传递的思路来看的话,不管执行任何方式的修改都会改变原内容,因此我们可以更加确认 Java 语言中只有值传递,如下图所示:

总结

通过本文的内容,我们可以得出:在 Java 语言中只有值传递,方法传参时只会传递副本信息而非原内容。我们还知道了基础数据类型会直接生成到栈上,而对象或数组则会在栈和堆上都生成信息,并将栈上生成的引用,直接指向堆中生成的数据,如下图所示:

  • 相关阅读:
    计算机mfc140.dll文件缺失的修复方法分析,一键修复mfc140.dll
    APS高级排程软件显着提升您企业的管理效益
    79、SpringBoot 整合 R2DBC --- R2DBC 就是 JDBC 的 反应式版本, R2DBC 是 JDBC 的升级版。
    模拟HashMap冲突
    JAVA concurrency -- AQS 源码详解
    Apache 的配置与应用
    分享一种非隔离控制三象限双向可控硅的产品级电路
    三元前驱体废水除钴项目,出水1mg/l以下
    【VS Code】推荐一套我非常喜欢的主题和字体样式
    nacos动态配置刷新机制原理
  • 原文地址:https://blog.csdn.net/weixin_62421895/article/details/126053679