Java值传递和引用传递

 

Java相关的面试经常会遇见这样的题目:

   private void function(int a) {
        a = 2;
    }

    @Test
    public void test() {
        int a = 1;
        function(a);
        System.out.println(a);// result == 1
    }

问最后的输入结果是什么,大家都知道这个结果是1.

仔细想想其实这个问题考察的是对于Java中引用传递和值传递的问题。

这里要引入一个概念,实际参数和形式参数,对于上面的代码,test方法中的int a = 1;最后作为实际参数传递到方法function()中,function方法的参数int a就是形式参数。

查资料得知:方法调用时,实际参数把它的值传递给形式参数,方法接收到的是原始参数的一个copy,此时内存中存在两个相等的基本数据类型,即实际参数和形式参数,后面方法中参数的修改都是对形参的修改,不影响实际参数。

引用传递,也成为地址传递,方法调用时实际参数的引用被传递给方法的对应的形式参数,方法接受的是原始对象的内存地址引用。在方法执行的时候,形参和实参内容相同,指向同一块内存地址,方法的执行对引用的操作将会影响到实际对象。

基本数据类型值传递


    private void f1(int a) {
        a = 2;
    }

    @Test
    public void main1() {
        int a = 1;
        f1(a);
        System.out.println(a);// result == 1
        // 对于基本数据类型是值传递,形参的值不会影响实参,也就是f1方法的参数a赋值了 a= 2,
        // 但是不会影响main1方法的实参a = 1,最后输入依然是1
    }

  

数组的传递: 

 private void f2(int[] c) {
        c[0] = 2;
    }

    @Test
    public void main2() {
        int[] a = new int[1];
        a[0] = 1;
        f2(a);
        System.out.println(a[0]);// result == 2  ???
       
    }

数组的数据保存和Java其他对象类型一样也是引用传递 ,main2方法中的数组a和f2方法的参数a传递的时引用指向的时同一片堆内存new int[1]的地址。 因此 方法修改了a[0] = 2也就是修改了堆中的对象,所以输入也变了(这里的引用传递也就是说f2方法的参数是把main2方法中对象的引用a传递了过来,实际上和f2方法的参数没有关系不管他是int[]a或者是int[]b)。所以f2方法最后修改了引用的值,结果输入2。

对于数组的操作对比如下代码

 private void f3(int[] a) {
        a = new int[1];
        a[0] = 2;
    }

    @Test
    public void main3() {
        int[] a = new int[1];
        a[0] = 1;
        f3(a);
        System.out.println(a[0]);// 结果是 1 result ==1
       
    }

new int[1] 在堆内存中分配了空间,int a[]指向了这个地址空间,只有调用数组的对象的属性或者对象本身是访问的是堆中的
对象,a[0] = 1;
 f3方法中的参数 int []a 被赋值了一个新创建的数组 new int[1]以后的修改都在这个对象中进行,不会修改原来main3中定义的的参数,所以不变。

字符串的传递

 @Test
    public void testStr() {
        String ss = "hello";
        change(ss);
        System.out.println(ss);// 结果:hello
    }


    private void change(String value) {
        value = value + "--world";
        System.out.println(value); // 局部结果:hello--world
    }

字符串的操作结果和值传递的结果一样。

对于Integer等包装类型的传递

 @Test
    public void testInteger() {
        Integer integer = 10;
        change(integer);
        System.out.println("原始值:"+integer);//结果:

    }

    private void change(Integer value) {
        value = +value;
        System.out.println("修改的value:" + value);
    }

包装类型数据的结果:

对于对象类型的操作

 @Test
    public void testStringBuilderStr() {
        StringBuilder ss = new StringBuilder("StringBuilder-hello");
        change(ss);
        System.out.println(ss);//结果:StringBuilder-hello--world
        // java对于对象的传递时引用传递,对于基本数据类型的传递是值传递
    }

    private void change(StringBuilder sb) {
        sb = sb.append("--world");
        System.out.println(sb.toString());
    }

使用StringBuilder创建一个对象传递到方法中,最后输入的结果是:StringBuilder-hello--world

我们能看到传递对象时最后把对象的值做了修改。

所以从上面的代码我们基本可以知道:

对于数组和其他对象类型的传递是引用传递,方法中会修改原始参数的值

对于基本数据类型,以及基本数据类型的包装类型和String在java中采用的是值传递,不会修改原始值

你可能感兴趣的:(java,基础)