Java是值传递还是引用传递?

当我们在调用一个有参方法时,会把实际参数传递给形式参数。
这个传递过程中有两种情况,分别是值传递和引用传递。
我们来看下程序语言中是如何定义和区分值传递和引用传递的。

值传递(pass by value)是指在调用方法时将实际参数拷贝一份传递到方法中,这样在方法中如果对参数进行修改,不会影响到实际参数
引用传递(pass by reference)是指在调用方法时将实际参数的地址传递到方法中。在方法中对参数进行的修改,会影响到实际参数

    public static void main(String[]args){
        int number=10;
        int i = System.identityHashCode(number);
        change(number);
//        System.out.println("***方法后****,内存地址为"+i);
        System.out.println("***方法后****,值为"+number);

    }

    public static void change(int a){
        a=20;
        int i = System.identityHashCode(a);
//        System.out.println("***方法中****,内存地址为"+i);
        System.out.println("***方法中****,值为"+a);
    }

上面代码里,我们在main方法声明一个变量number,通过change方法想要修改number的值,但是结果如下:

***方法中****,值为20
***方法后****,值为10

发现,change方法并没有改变实际参数(number)的值。
有人通过这个例子就确定了,java就是值传递。
但也有人不认可,认为是引用传递的,看下代码:

    public static void main(String[]args){
        Dog dog=new Dog();
        dog.setAge(1);
        change(dog);
        System.out.println("***方法后****,年龄为"+dog.getAge());

    }

    public static void change(Dog dog){
        dog.setAge(2);
        System.out.println("***方法中****,年龄为"+dog.getAge());
    }    public static void main(String[]args){
        Dog dog=new Dog();
        dog.setAge(1);
        change(dog);
        System.out.println("***方法后****,年龄为"+dog.getAge());

    }

    public static void change(Dog dog){
        dog.setAge(2);
        System.out.println("***方法中****,年龄为"+dog.getAge());
    }

上面代码里,change方法中传入的实际参数是一个dog对象,结果输出如下:

***方法中****,年龄为2
***方法后****,年龄为2

这个时候参数的值发生了改变,有人就会得出结论(错误的):java中传递普通类型是值传递,传递对象是引用传递。

接下来,再看一段代码:

public static void main(String[]args){
        String str="hello";
        change(str);
        System.out.println("***方法后****,内存地址为"+System.identityHashCode(str));
        System.out.println("***方法中****,值为"+str);

    }

    public static void change(String a){
        System.out.println("***方法中****,第一次内存地址为"+System.identityHashCode(a));
        a="world";
        System.out.println("***方法中****,第二次内存地址为"+System.identityHashCode(a));
        System.out.println("***方法中****,值为"+a);
    }

上面代码的输出结果为:

***方法中****,第一次内存地址为460141958
***方法中****,第二次内存地址为1163157884
***方法中****,值为world
***方法后****,内存地址为460141958
***方法中****,值为hello

都知道,String str="hello" 等同于 String str=new String("hello")。
str作为对象通过change方法传递,按照之前的例子,此时传递的对象应该是改变实际参数值啊。
其实,在方法调用前,我们创建了str引用,指向了“hello”,然后调用方法时,将str引用作为实际参数进行传递。此时,a变量的值等同于str的值,值为引用地址(0x10),同时指向“hello”。
然后我们让a=“world”,意思就是让a重新申请一块内存空间(创建对象),覆盖原来的引用地址(新的地址0x11)。此时a和str已经毫无关系,所以在被调方法中输出的都是a的值。但是主调方法中输出str的值还是原来的对象没有发生变化,依然是“hello”。


image.png

值传递和引用传递的区别:
值传递会拷贝一个副本,引用传递不会创建副本。

java中,
值传递中参数是基本类型,传递的是字面量值得拷贝。
值传递中参数是引用类型,传递的是该变量所引用的对象在堆中地址值的拷贝。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。