标签:
讨论这个问题,我们首先应该明确一点:
什么是值传递?什么是引用传递?
值传递:传递过程中,将变量的值拷贝一个副本,用这个副本值来对新变量完成初始化;
传递结果:两个变量的值相同,但互相独立。
引用传递:传递过程中,只传递原变量的指针副本,新变量接受这个指针副本;
传递结果:两个变量指向同一个对象。
由以上可知:值传递与引用传递最大的区别在于:传递过程中是否发生了对象的拷贝
在一些java和javascript的书中,对于参数传递的过程都强调:只有值传递。这种理解或许存在一定的误区,或者说这种认识是比较模糊的,不能算错但让人难以理解,因为这两种语言中非基本类型对象很明显传递的是一个引用,可为什么非要说是按值传递?
经过分析可以想象,这种说法的内涵是:对于非基本类型的数据,变量在栈中存储的内容本身就是一个指针地址,而发生传递时,传递的并不是引用本身,而是引用的副本(拷贝)【这是在描述栈上的变化,即:无论传递的是一个基本类型的值还是其他类型的引用副本,这当中本身就发生了拷贝操作】。
var person = new Object(); person.name = ‘sunf‘; function change(obj){ obj.name = ‘fanS‘; obj.age = 18; } change(person); console.log(person.name);
在上面这个例子的过程:
1:创建一个对象person。
2:给person添加一个name属性,并赋值sunf。
3:调用函数change(),将person的引用副本传递给函数change()的局部变量,此时obj指向与外部的person相同的对象。
4:操作局部变量obj,相当于直接操作位于堆中的对象。于是输出时候person.name被改变。
var person = new Object(); person.name = ‘sunf‘; function change(obj){ obj = new Object(); obj.name = ‘fanS‘; } alert(person.name);
在上面这个调用例子用:change中的obj变量在函数开始运行的时,将原先的引用替换成了一个对新对象的引用,此时obj与外部的person没有任何关系,所以在函数中改变obj的属性,person不会有任何变化。
class Person{ String name; String age; public static void main(String[] args){ Person person = new Person(); person.name = "sun"; person.age = 18; change(person); } public static void change(Person methodPerson){ methodPerson.name = "fan"; //由于外部的person与方法内部methodPerson指向同一个对象 //所以修改methodPerson相当于修改person methodPerson = new Person(); //methodPerson指向新的对象,与原来的关系断开。 methodPerson.name = ‘hhhh‘; //外部person不会变化 } }
在非基本类型参数传递时,java与javascrpt采用的手段完全相同,都是通过引用副本操作堆中的对象。
由以上例子可得出结论:发生参数传递时引用的副本可以被改变,但是引用本身不会被改变(其实根本拿不到引用本身,它只存在于最初的那个变量)。(换句话说就是:方法体内对引用副本的改变与外部变量的引用本身无关)
从这些例子看来,两种语言都是值传递这个话,虽然不能算错,但表达的并不完整,所以我更倾向于“基本类型按值传递,非基本类型按引用传递”这样的理解。因为这样更容易理解参数在传递过程中发生的变化。
另外在java语言中,String有一个很有意思的现象。首先String是引用类型,我们从以上结论知道,引用类型是按引用传递。
class Person{ public static void main(String[] args){ String name = "sunf"; change(name); System.out.println("name--->" + name); } public static void change(String str){ str = "hello " + str; System.out.println("str--->"+ str); } } //打印结果: //str---> hello sunf //name---> sunf
从以上结果的运行看来,String类型仿佛是按值传递的,但是不要忘了,String类是final的他不可变化,任何对String类型对象做的修改,都会创建一个新的对象。所以在函数change中第一行,str实际上是将其指针指向了一个新的对象,所以str与外部的name无关。
标签:
原文地址:http://my.oschina.net/dlam/blog/486421