java中永远都是值传递,没有引用传递对吗?

错误理解①:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。
错误理解②:Java是引用传递。
错误理解③:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。

基本数据类型: byte char short int long float double boolean
引用数据类型: 接口类型(List) 、类类型(ArrayList) 、数组(int [] arr)、String

1、基本数据类型参数传递

基本数据类型中,传递的是值;形参是对实参的一份临时拷贝,修改形参的值不会对实参产生任何影响。

例子:

public class Test {
    public static void main(String[] args) {
        int a = 0;
        modify(a);
        System.out.println("实参:"+a);
    }
    private static void modify(int A) {
        A = 999;
        System.out.println("形参:"+A);
    }
}
-------------------------------------------------
打印结果:
形参:999
实参:0

下面通过画图分析内存中的变化来理解为什么会这样

  • 变量main 方法中的a是基本类型,所以它的值0直接存储在栈中。
  • 调用 modify() 方法的时候,将为实参a创建一个副本(形参 A),它的值也为0,开辟了新的内存空间,在栈中的其他位置。
  • 对形参A的任何修改都只会影响它自身而不会影响实参。
    在这里插入图片描述
    可见,modify方法内部对形参A的值的修改并没有改变实际参数a的值。那么,按照上面的定义,
    有人得到结论:Java的方法传递是值传递。
    这显然是错误的的,请往下看

2、引用数据类型参数传递

首先对于Demo demo = new Demo()这样的代码
请问demo 是引用还是对象?
通过分解我们来看
Demo demo;
demo = new Demo();

  • 假如 demo是对象的话,就不需要通过 new 关键字创建对象了,那也就是说,demo并不是对象,在“=”操作符执行之前,它仅仅是一个变量
  • 真正的对象是new Demo( ),它是对象,存储于堆中;
  • “=”操作符将对象的引用赋值给了 demo变量,于是 demo此时应该叫对象引用,它存储在栈中,保存了对象在堆中的地址

每当引用类型作为参数传递时,都会创建一个对象引用(实参)的副本(形参),该形参保存的地址和实参一样。

class Demo {
    public String name;
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.setName("包包子");
        function(demo);
        System.out.println("主函数"+demo);
    }
    public static  void function(Demo demoCopy) {
        demoCopy.setName("九度");
        System.out.println("function函数"+demoCopy);
    }
}
-------------------------------------------------
打印结果:
function函数Demo {name='九度'}
主函数Demo {name='九度'}

通过画图来理解一下

  • 在调用 function() 方法时,实参demo和在栈中创建了一个新的副本demoCopy, 它的值也是"包包子"在堆中的内存地址, 与demo指向的对象是一致的
  • function()方法中,修改了形参demoCopy的name为"九度",意味着对象demoCopy的 name从"包包子"变成了"九度", 而两个引用指向的是同一块内存空间,所以原本demo对象的值也会跟着被修改

举个生活中的例子来理解一下,你有一把钥匙能打开你家的房门,你重新复制了一把新的钥匙给了你朋友,因为这两把钥匙都能打开你家的这扇门,所以假如当你朋友开了门去你家把电视剧砸了,这对你有影响吗?当然是的,因为开的是你家的门。
在这里插入图片描述
看到这里,有人得出一个新的结论:Java的方法中,在传递普通类型的时候是值传递,在传递对象类型的时候是引用传递。
这显然是错误的结论,不信请往下继续看

3、"传引用"一定能成功修改值吗?

请看这个例子

class Demo {
public String name;
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.setName("包包子");
        function(demo);
        System.out.println("主函数"+demo);
    }
    public static  void function(Demo demoCopy) {
        demoCopy = new Demo();
        demoCopy.setName("小鱼干");
        System.out.println("function函数"+demoCopy);
    }
}
-------------------------------------------------
打印结果:
function函数Demo{name='小鱼干'}
主函数Demo{name='包包子'}

你一定很疑惑,我不是明明向function函数中传了引用吗,为什么没能成功修改主函数中对象的属性???
下面通过画图来分析一下为什么传引用不一定会成功修改值,最后再告诉你为啥Java中永远是值传递
在这里插入图片描述

  • 当我们在main中创建一个Demo对象的时候,在堆中开辟一块内存,其中保存了name数据。然后demo持有该内存的地址0x7796(图①)。

  • 当尝试调用function方法,并且demo作为实际参数传递给形式参数demoCopy的时候,会把这个地址0x7796交给user,这时,user也指向了这个地址(图②)。

  • 在function方法内对参数进行修改的时候,即demoCopy = new Demo();,会重新开辟一块0X6688的内存,赋值给demoCopy。后面对demoCopy的任何修改都不会改变原内存0X7796的内容(图③)。

上面这种传递是什么传递?肯定不是引用传递,如果是引用传递的话,在执行demoCoopy= new Demo();的时候,实际参数的引用也应该改为指向0X6688,但是实际上并没有。
通过以上分析,这里是把实际参数的引用的地址复制了一份,传递给了形式参数。所以,上面的参数其实是值传递,把实参对象引用的地址当做值传递给了形式参数

Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用,即一个地址。

再举个生活中的例子:
还是你有一个房子一把钥匙,你复制了一把钥匙给你的朋友;但是你朋友中途自己买了一间新房子附带一把新房子的新钥匙。持有的钥匙从你的更新为新钥匙,你朋友拿着新钥匙打开了新房子,砸了里面的电视机,请问这对你家的电视机有影响吗,显然没有,因为操作的都不是一个房子里的电视机

综上:正确结论 Java中只有值传递,没有引用传递!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值