java是按值调用(值传递)还是按引用调用(引用调用)


java是按值调用还是按引用调用,
该问题一般是相对函数而言,就是java中的方法参数。
程序设计语言中有关参数传递给函数,两个专业术语

  • 按值调用/传递(call by value):是指在调用函数时将实际参数的值复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
  • 按引用调用/传递(call by reference):是指在调用函数时将实际参数的地址(c语言中指针)直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数

按值调用与引用调用的区别:实参到底有没有被复制一份给形参,能否修改传进来的值(实参)

值传递引用传递
根本区别会创建副本不创建副本
所以函数中无法改变原始对象函数中可以改变原始对象

java程序设计语言采用了按值调用,即java中不存在引用调用
也就是方法得到的是所有参数值的一个拷贝,方法并不能修改传递给它的任何参数变量的内容

基本数据类型

public class Test {
    private static int x = 10;

    public static void main(String[] args) {
        System.out.println("before "+x);
        change(x);
        System.out.println("after "+x);
    }

    private static void change(int value) {
        value = 30;
        System.out.println("change "+value);
    }
}

输出结果:

before 10
change 30
after 10

分析:
在这里插入图片描述
1)value被初始化为x值的一个拷贝(也就是10)
2)value被乘以3后等于30,但注意此时x的值仍为10
3)这个方法结束后,参数变量value不再使用,被回收

结论:当方法参数类型为基本数据类型时,方法不能修改参数

引用数据类型

class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Test {

    public static void main(String[] args) {
        Student value = new Student("zhang");
        System.out.println("before " + value.getName());
        change(value);
        System.out.println("after " + value.getName());
    }

    private static void change(Student student) {
        student.setName("wang");
        System.out.println("change " + student.getName());
    }
}

运行结果

before zhang
change wang
after wang

分析:
在这里插入图片描述
1)student变量初始化为value值的拷贝,是一个对象的引用
2)调用student变量的set方法作用在这个引用对象上,user和student同时引用的User对象内部值被修改
3)方法结束后,student变量不再使用,被释放,而value保持修改值
结论:当传递方法参数类型为引用数据类型时,方法可以修改参数

把实参对象引用的地址当做值传递给了形式参数
如果传递的是地址,看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。

java引用数据类型,拷贝实参(实参是指向堆的引用)的复制,修改复制值指向的堆中数据,
修改的虽然是拷贝数值,但实参拷贝和实参指向同一堆,所以实参指向的堆也被改变了,但改变的并不是实参本身 (指向那个堆)。

进一步证明java 是值传递

通过java引用对象的例子,可能就觉得java同时拥有按值调用和按引用调用,但是java中确实只有按值调用
例子:

class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class Test {

    public static void main(String[] args) {
        Student value = new Student("zhang");
        System.out.println("before " + value.getName());
        change(value);
        System.out.println("after " + value.getName());
    }

    private static void change(Student student) {
        student = new Student("wang");
        System.out.println("change " + student.getName());
    }
}

输出

before zhang
change wang
after zhang

在这里插入图片描述
1)student变量初始化为value值的拷贝,是一个对象的引用
2)student指向新的堆,并设置为 “wang”
3)方法结束后,student变量不再使用,被释放,而value还是原来的
如java果是引用传递,没有拷贝形参,那value也会指向"wang",但并不是,说明拷贝了形参,进一步证明java 是值传递

举个例子

1)值传递:你有一把钥匙,当你的朋友想要去你家的时候,如果你直接
把你的钥匙给他了,这就是引用传递。这种情况下,如果他对这把钥匙做了什么事情,比如对钥匙加工,更改钥匙能开的门,那么这把钥匙还给你的时候,钥匙开不了以前的门了,只能开新的门。

2)引用传递:你有一把钥匙,当你的朋友想要去你家的时候,你复刻了一把新钥匙给他,自己的还在自己手里,这就是值传递。这种情况下,他对这把钥匙做什么都不会影响你手里的这把钥匙。

3)Java值传递也能改变堆中数据:但是,不管上面那种情况,你的朋友拿着你给他的钥匙,进到你的家里,把你家的电视砸了。家中都会受到影响。

https://blog.csdn.net/javazejian/article/details/51192130
https://blog.csdn.net/weixin_44509889/article/details/93347191
https://www.zhihu.com/question/31203609

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值