值传递还是引用传递?

190 阅读2分钟

先说结论:无论是java还是go,都只有值传递,没有引用传递。

所谓值传递就是实参通过拷贝一份内容传递给形参,引用传递是实参将引用的对象在堆中的地址传递给形参,形参改变会影响到实参。

先以java举例:

public static void main(String[] args) {
    int a = 10;
    int b = 20;
    swap(a, b);
    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

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
a = 10
b = 20

可以看到传递基本类型时,形参(a, b)的改变并没有影响到实参(a, b)

再继续看下面的案例

public class Animal {
    private String type;
    public Animal(String type){    
        this.type = type;
    }
    public String getType() {    
        return type;
    }
}

public static void main(String[] args) {
    Animal dog = new Animal("dog");    Animal cat = new Animal("cat");    swap(dog, cat);    System.out.println("dog:" + dog.getType());    System.out.println("cat:" + cat.getType());}

public static void swap(Animal dog, Animal cat) {    Animal temp = dog;    dog = cat;    cat = temp;    System.out.println("dog:" + dog.getType());    System.out.println("cat:" + cat.getType());}

这段代码传递的是引用类型,执行结果如下

dog:cat
cat:dog
dog:dog
cat:cat

可以看到,形参的改变并没有影响到实参,所以即使传递引用类型,java依然是值传递。

而传递的这个值其实是实参的拷贝地址,指向的都是同一个对象,swap方法里交换也只是实参拷贝两个地址之间的交换,并不会影响到真正的实参,入下图所示:

再看一下go语言中

func main(){
    student := &Student{
        name: "a",
    }
    teacher := &Teacher{
        name: "b",
    }
    fmt.Println(&student)
    fmt.Println(&teacher)
    Swap(student, teacher)
}

type Student struct{
    name string
}
type Teacher struct {
    name string
}

func Swap(student *Student, teacher *Teacher)  {
    fmt.Println(&student)
    fmt.Println(&teacher)
}

我们直接打印指针变量地址,结果如下:

0xc000012028
0xc000012030
0xc000012040
0xc000012048

可以看到传递过程中,地址发生了变化,这说明传递的是一份拷贝,所以go也是值传递。