【Java基础】面试官:Java 对象是值传递还是引用传递?

前言

  • Java 值传递和引用传递一直值讨论比较多的话题,本文将结合概念和案例做一个比较详细的介绍。

形参和实参

  • 我们先了解一点前置知识,形参和实参,先说概念:形参出现在函数定义中,在整个函数体内都可使用,离开函数体则不可使用。实参出现在主调函数中,进入被调函数后,不能使用。
Java 复制代码
// 案例
public class MainTest {
    public static void main(String[] args) {
        // 这里的 a 就是实参
        int a = 1;
        func(a);
    }

    // param 则是形参
    public static void func(int param) {
        System.out.println(param);
    }
}

回顾一下 Java 内存管理

  • 我们先回顾一下这张熟悉的 Java 内存管理图片,在后文中我们会使用到。

值传递和引用传递

  • 我们先了解一下值传递和引用传递的概念:值传递是指在调用方式时,将实参的值拷贝一份给形参,对形参的修改不影响实参。引用传递也叫地址传递,指在调用方法时将实参的地址传递给形参,对形参的修改将影响实参的值,即传递的是实参的内存地址。

普通变量传递为值传递

  • 普通变量为值传递,这个大家应该比较好理解,其实就是拷贝了一份实参的值到形参中。
Java 复制代码
// 继续上面的案例
public class MainTest {
    public static void main(String[] args) {
        // 这里的 a 就是实参
        int a = 1;
        func(a);
        System.out.println("修改后实参的值:" + a);
    }

    // param 则是形参
    public static void func(int param) {
        System.out.println("形参的值:" + param);
        param++;
        System.out.println("修改后形参的值:" + param);
    }
}

// 输出
形参的值:1
修改后形参的值:2
修改后实参的值:1
  • 可以看到实参的值并未因为形参的修改而改变,即 Java 的普通变量传递为值传递。实际上是将实参的值拷贝了一份到栈帧的局部变量表中。

对象类型的传递是引用传递?

  • 比较有争议的是对象类型的传递,有的人认为是值传递,有的人认为是引用传递,我们先来看看两个案例:
Java 复制代码
// 案例一
public class MainTest {
    public static void main(String[] args) {
        TestObj testObj = new TestObj(0);
        System.out.println("原始实参的值:" + testObj.a);
        func(testObj);
        System.out.println("修改后实参的值:" + testObj.a);
    }

    public static void func(TestObj obj) {
        System.out.println("形参的值:" + obj.a);
        obj.a = 1;
        System.out.println("修改后形参的值:" + obj.a);
    }
}
class TestObj {
    int a;

    public TestObj(int a) {
        this.a = a;
    }
}

// 输出
原始实参的值:0
形参的值:0
修改后形参的值:1
修改后实参的值:1

// 对形参的修改影响了实参,难道是引用传递?那再看看下面的案例

// 案例二
public class MainTest {
    public static void main(String[] args) {
        TestObj testObj = new TestObj(0);
        System.out.println("原始实参的值:" + testObj.a);
        func(testObj);
        System.out.println("修改后实参的值:" + testObj.a);
    }

    public static void func(TestObj obj) {
        System.out.println("形参的值:" + obj.a);
        // 和案例一不同的改动
        obj=new TestObj(1);
        System.out.println("修改后形参的值:" + obj.a);
    }
}
class TestObj {
    int a;

    public TestObj(int a) {
        this.a = a;
    }
}

// 输出
原始实参的值:0
形参的值:0
修改后形参的值:1
修改后实参的值:0
  • 看到上面的两个案例,可能大家就比较疑惑了,几乎是两个相同的案例,都是对形参进行修改,一个却影响了实参,一个却没有影响实参,其实这就要从 Java 的内存管理说起。前面我们介绍了 Java 内存模型,我们看看两次调用形参和实参在 Java 内存中的分布。
  • 这样是不是很清晰了,Java 对象类型确实传递的是引用但只是引用的一个拷贝,可以理解为传递的是引用的拷贝值,对拷贝引用的修改并不会影响原引用,因此 Java 中只有值传递。
相关推荐
爱上语文15 分钟前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people19 分钟前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
qmx_071 小时前
HTB-Jerry(tomcat war文件、msfvenom)
java·web安全·网络安全·tomcat
为风而战1 小时前
IIS+Ngnix+Tomcat 部署网站 用IIS实现反向代理
java·tomcat
技术无疆3 小时前
快速开发与维护:探索 AndroidAnnotations
android·java·android studio·android-studio·androidx·代码注入
罗政6 小时前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
架构文摘JGWZ6 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
拾光师7 小时前
spring获取当前request
java·后端·spring
aPurpleBerry7 小时前
neo4j安装启动教程+对应的jdk配置
java·neo4j
我是苏苏7 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言