值传递和引用传递


首先要明确的是:“对象传递(数组、类、接口)是引用传递,原始类型数据(整型、浮点型、字符型、布尔型)传递是值传递。”

那么什么是值传递和应用传递呢?

值传递是指对象被值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。(因为值传递的时候,实际上是将实参的值复制一份给形参。)

引用传递是指对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有的对象上。(因为引用传递的时候,实际上是将实参的地址值复制一份给形参。)

有时候面试官不是单纯问你“Java中是值传递还是引用传递”是什么啊,骚年?而是给出一个例子,然后让你写出答案,这种也常见在笔试题目中!所以,非常重要了,请看下面的例子:

值传递和引用传递实例

1. 值传递

public static void main(String[] args) {
    int num1 = 10;
    int num2 = 20;

    swap(num1, num2);

    System.out.println("num1 = " + num1);
    System.out.println("num2 = " + num2);
}

public static void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;

    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

结果

a = 20
b = 10
num1 = 10
num2 = 20

解析
在swap方法中,a、b的值进行交换,并不会影响到num1、num2。因为,a、b中的值,只是从num1、num2的复制过来的。
也就是说,a、b相当于num1、num2的副本,副本的内容无论怎么修改,都不会影响到原件本身。
2. 引用传递

public static void main(String[] args) {
    int[] arr = {1,2,3,4,5};

    change(arr);

    System.out.println(arr[0]);
}

public static void change(int[] array) {
//将数组的第一个元素变为0
    array[0] = 0;
}

结果

1
0

解析
无论是主函数,还是change方法,操作的都是同一个地址值对应的数组。 。因此,外部对引用对象的改变会反映到所有的对象上。

一些特殊的例子

1. StringBuffer类型传递

// 测试引用传递:StringBuffer
@org.junit.Test
public void method1() {
    StringBuffer str = new StringBuffer("半夏有你");
    System.out.println(str);
    change1(str);
    System.out.println(str);
}

public static void change1(StringBuffer str) {
    str = new StringBuffer("abc");//输出:“半夏有你”
//str.append("欢迎大家关注");输出:“半夏有你欢迎大家关注”
    //str.insert(3, "(编程)");//输出:“半夏有你”
}

结果

半夏有你
半夏有你

解析
很多要这个时候要问了:StringBuffer创建的明明也是对象,那为什么输出结果依然是原来的值呢?

因为在change1方法内部我们是新建了一个StringBuffer对象,所以str指向了另外一个地址,相应的操作也同样是指向另外的地址的。

那么,如果将change1方法改成如下图所示,想必大家应该知道输出什么了,如果你还不知道,那可能就是我讲的有问题了,我反思(开个玩笑,上面程序中已经给出答案):

public static void change1(StringBuffer str) {

    str.append("欢迎大家关注");
    str.insert(3, "(编程)");
    
}

2. String类型传递

// 测试引用传递:Sring
@org.junit.Test
public void method2() {
    String str = new String("半夏有你");
    System.out.println(str);
    change2(str);
    System.out.println(str);
}

public static void change2(String str) {
    // str="abc"; //输出:半夏有你
    str = new String("abc"); //输出:半夏有你
}

结果

半夏有你
半夏有你

可以看到不论是执行str="abc;"还是str = new String("abc");str的输出的值都不变。
按照我们上面讲“StringBuffer类型传递”的时候说的,str="abc;"应该会让str的输出的值都不变。为什么呢?因为String在创建之后是不可变的。
3. 一道类似的题目
下面的程序输出是什么?

public class Demo {
    public static void main(String[] args) {
        Person p = new Person("张三");

        change(p);

        System.out.println(p.name);
    }

    public static void change(Person p) {
        Person person = new Person("李四");
        p = person;
    }
}

class Person {
    String name;

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

很明显仍然会输出张三。因为change方法中重新创建了一个Person对象。

那么,如果把 change方法改为下图所示,输出结果又是什么呢?

public static void change(Person p) {
    p.name="李四";
}

答案我就不说了,我觉得大家如果认真看完上面的内容之后应该很很清楚了。

声明:半夏有你|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 值传递和引用传递


站在巨人的肩膀上,我们渺小到不可一世。