Java和Go都没有按引用传递

很多程序设计语言(特别是, C++ 和 Pascal) 提供了两种参数传递的方式:值调用和引
用调用。有些程序员(甚至本书的作者)认为 Java 程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。首先,编写一个交换两个雇员对象的方法:

public static void swap(Employee x , Employee y) // doesn't work
{
    Employee temp = x;
    x = y;
    y = temp;
}

如果Java对象采用的是引用调度,那么这个方法就应该能够实现交换数据的效果:

Employee a = new Employee("Alice", . . . );
Employee b = new Employee("Bob", . . . );
swap(a, b);
// does a now refer to Bob, b to Alice?

但是,方法并没有改变存储在变量 a 和 b 中的对象引用。swap 方法的参数 x 和 y 被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝。

// x refers to Alice, y to Bob
Employee temp = x;
x = y;
y = temp;
// now x refers to Bob, y to Alice

最终,白费力气。在方法结束时参数变量 X 和 y 被丢弃了。原来的变量 a 和 b 仍然引用这个方法调用之前所引用的对象(如图 4 - 8 所示 )
Java和Go都没有按引用传递_第1张图片

这个过程说明:Java 程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。 

==============以上引用自java核心知识基础卷==========================

Go语言和java一样没有引用传递,即没有和C++一样以int&为类型的引用变量,虽然Go和C++一样有指针。

Go 值传递参数(按值传递)演示,类似于Java的值传递,因为改变的是形参副本指向的值地址,所以实参不变,是按值传递

package main
import "fmt"
func demo(i int, s string) {
	i = 5
	s = "改变"
}
func main() {
	i := 1
	s := "原值"
	demo(i, s)
	fmt.Println(i, s) //输出:1 原值
}

引用传递代码(按值传递)演示,类似于Java的引用传递,传递的数组变量相当于是数组的地址,改变数组内一项的址相当于改变数组属性的值,并没有改变数组变量指向的地址,所以是按值传递

package main
import "fmt"
func demo(arg []int) {
   arg[len(arg)-1] = 110
}
func main() {
   s := []int{1, 2, 3}
   demo(s)
   fmt.Println(s) //输出:[1 2 110]
}

改用指针 (按值传递)演示,类似于Java的引用传递,传递的指针变量相当于值的地址,函数改变的是地址存的值,而没有改变指针变量指向的地址,所以是按值传递。

package main
import "fmt"
//行参指针类型
func demo(i *int, s string) {
   //需要在变量前面带有*表示指针变量
   *i = 5
   s = "改变"
}
func main() {
   i := 1
   s := "原值"
   //注意此处第一个参数是i的地址,前面要加&
   //s保留为值类型
   demo(&i, s)
   fmt.Println(i, s) //输出:5 原值
}

 如果试着在函数里给i 指针变量赋予另一个值的地址,会发现实参并没有变,所以用指针传递也是按值传递。

package main
import "fmt"
//行参指针类型
func demo(i *int, s string) {
   //需要在变量前面带有*表示指针变量
   //给i赋予j的地址会发现没有变化
   j := 5
   i = &j
   s = "改变"
}
func main() {
   i := 1
   s := "原值"
   //注意此处第一个参数是i的地址,前面要加&
   //s保留为值类型
   demo(&i, s)
   fmt.Println(i, s) //输出:1 原值
}

你可能感兴趣的:(数据与算法)