JAVA引用传递和值传递

287 阅读3分钟

这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战

前言

今天日常摸鱼的时候,群里闲聊,有人问JAVA中参数传递的时候,传递的是参数值还是引用?当时第一反应有点闷,想到了基本类型和引用类型,回了句好像是基础类型是值传递,引用类型是引用传递,好像说了,又好像什么也没说,群里也没有给出权威性的答案,然后我网上冲浪一番后,给出我的答案。

Java是值传递!Java是值传递!Java是值传递!

论证

无论是基本类型具体值还是引用类型的引用地址值都是值传递。

口说无凭,我们敲代码证明一下 看下面这个例子

package com.yang.passbyvalue;
import java.util.Arrays;
/**
 * 基本数据类型传的是克隆的一个值,
 * 引用类型传的是克隆指向对象地址值的一个值
 */
public class Demo {
    public static void change(int a) {
        a = 2;
        System.out.println("我是方法里的a:" + a);
    }
    public static void changArray(int[] data) {
        data[0] = 3;
        data[1] = 4;
        System.out.println("我是方法里的data:" + Arrays.toString(data));
    }
}

class Test {
    public static void main(String[] args) {
        //初始化基本数据类型
        int a = 0;
        System.out.println("我是初始化的a:" + a);
        Demo.change(a);
        System.out.println("我是change后的a:" + a);
        
        //初始化引用数据类型
        int[] data = {1, 2};
        System.out.println("我是初始化的data:" + Arrays.toString(data));
        Demo.changArray(data);
        System.out.println("我是change后的data:" + Arrays.toString(data));

    }
}

定义一个基础类型a=1调用change()将赋值改为2,然后定义一个引用类型数据,然后调用changArray()将数组中的值修改掉,然后分别打印方法调用前和调用后的结果。 我们可以带着心里的答案去验证一下。

我是初始化的a:0
我是方法里的a:2
我是change后的a:0
我是初始化的data:[1, 2]
我是方法里的data:[3, 4]
我是change后的data:[3, 4]

结果,基础类型值没有改变,引用类型值随方法改变而改变了

基础数据类型传递的是一份数据拷贝,所以在change()里修改了方法里的a的值并不会影响初始值,而对于数组(引用类型),changArray()修改了地址引用指向的对象的值,所以原来引用指向该对象的值都随之改变了。

看到这里,貌似我最初的解释是合理的,心里有点小窃喜,但是,事实并不是这样。 再来看看下面这个例子

package com.yang.passbyvalue;
public class StringDemo {
    public static void change(String s) {
        s = "aaa";
        System.out.println("我是方法里的s:" + s);
    }
}

class StringDemoTest {
    public static void main(String[] args) {
        String s = "a";
        System.out.println("我是初始化的s:" + s);
        StringDemo.change(s);
        System.out.println("我是修改后的s:" + s);

    }
}
我是初始化的s:a
我是方法里的s:aaa
我是修改后的s:a

String类型作为引用数据类型,为什么在方法里修改了,但是没有影响原先的值?

我们知道String不可变,String底层是被final 修饰的 char[],值是不能被修改的。

字面值 "a" 初始化的时候,会先将 "a" 放进字符串常量池中, s 保存的是引用地址值,当调用change()方法时,将地址值传过去,s = "aaa";会先去常量池中找 "aaa",找到返回 "aaa"的地址引用,找不到创建一个"aaa",返回新建的"aaa"的地址引用,新的引用覆盖传过来的引用 s,但是初始化的 s任然保存的是指向 "a"的地址引用。这恰恰说明了 Java 里是值传递。

总结

有些时候我们觉得掌握的知识并不一定可靠,正是因为很多这种模糊导致了我们在工作或者面试时候的不自信,从另一方面也反映出来自己基础的不扎实,后期这块还是要不断加强,不断学习。