参数传递方式的一些总结_Parameter passing method

程序中的参数传递分为:值传递,引用传递,值结果传递,名字传递 四种.在java和javascript中则似乎只有两种.

值传递(pass by value)
在这个机制中,自变量是在调用时计算的表达式,而且在执行过程时,它们的值就成为了参数的值.

引用传递(pass by reference)
在引用传递中,自变量必须与分配的地址一起变化(至少是原则上).并非传递变量的值,引用传递的是变量的地址,因此参数就变成了自变量的别名,而且在参数上发生的任何
变化都会出现在自变量上.

值结果传递(pass by value-result)
除了未建立真正的别名之外,这个机制得到的结果与引用传递类似:在过程中复制和使用自变量的值,然后当过程退出时,再将参数的最终值复制回自变量的地址.

名字传递(pass by name)
这是传递机制中最复杂的参数了。由于名字传递的思想是直到在被调用的程序真正使用了自变量(作为一个参数)之后才对这个自变量赋值,所以它还称作延迟赋值(delayed evaluation).

注:自变量(independent variable)一词来自数学。在数学中,y=f(x)。在这一方程中自变量是x,因变量(dependent variable)是y.如果x取任意一个量,y都有唯一的一个量与x对应,那么相应地x就叫做这个函数的自变量. x的取值范围叫做函数的定义域(domain),对应y的值叫做函数值(function value),函数值的集合叫做值域(range).

Java 应用程序中的变量可以为以下两种类型之一:引用类型或基本类型。当作为参数传递给一个方法时,处理这两种类型的方式是相同的。两种类型都是按值传递的;没有一种按引用传递。这是一个重要特性,正如随后的代码示例所示的那样。

在继续讨论之前,定义 按值传递和 按引用传递这两个术语是重要的。 按值传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的一个副本。因此,如果函数修改了该参数,仅改变副本,而原始值保持不变。 按引用传递意味着当将一个参数传递给一个函数时,函数接收的是原始值的内存地址,而不是值的副本。因此,如果函数修改了该参数,调用代码中的原始值也随之 改变。

java中基本类型都为值传递,即使创建基本类型的对象,如:

public class Test {
public void changeString(String s) {
s = “hi”;
}
public void changeInt(int s) {
s = 100;
}
public static void main(String[] args) {
Test test = new Test();
//创建string对象
String a = new String(“aa”);
String b = “bb”;
test.changeString(a);
test.changeString(b);
System.out.println(a); //结果为 aa
System.out.println(b); //结果为 bb

//创建Integer对象
Integer c = new Integer(1);
int d = 2;
test.changeInt(c);
test.changeInt(d);
System.out.println(c); //结果为 1
System.out.println(d); //结果为 2
}
}

说明只是进行值的传递,原来赋值的变量没有改变.但是如果为数组或者对象,则会进行引用传递:

public class Test {
public void changeArray(int[] s) {
s[0] = 100;
}
public void changeArray(String[] s) {
s[0] = “aa”;
}
public static void main(String[] args) {
Test test = new Test();
// 创建int型数组对象
int[] e = { 1, 2 };
// 创建字符串型数组对象
String[] f = { “aa”, “bb” };
test.changeArray(e);
test.changeArray(f);
System.out.println(e[0]); //结果为100
System.out.println(f[0]); //结果为aa
}
}

注:其它基本类型如:short,long,byte,float,double都为值传递,可以自己进行测试.

同样,可以看看对象的参数传递机制:

public class Test {
private String name;
private int age;
public Test() { }
public Test(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void changeTest(Test t) {
t.name = “rain”;
t.age = 33;
}
public static void main(String[] args) {
Test test2 = new Test(“bob”,22);
test2.changeTest(test2);
System.out.println(test2.getName()); //结果为rain
System.out.println(test2.getAge()); //结果为33
}
}

javascript也有相同的参数传递机制:

<script type=”text/javascript”>
//创建对象
var man = {name:””,age:0};
//创建数组
var array = [1,2];
function changeBoolean(temp){
temp = false;
}
function changeNum(temp){
temp = 100;
}
function changeString(temp){
temp = “aa”;
}
function changeObject(o){
o.name = “hello”;
}
function changeArray(a){
a[0] = 100;
}

function test(){
var a = 1;
var a2 = new Number(1.2);
var b = “bb”;
var b2 = new String(“bbb”);
var c = true;

changeNum(a);
alert(a); //结果为1
changeNum(a2);
alert(a2); //结果为1.2
changeString(b);
alert(b); //结果为bb
changeString(b2);
alert(b2); //结果为bbb
changeBoolean(c);
alert(c); //结果为true
changeObject(man);
alert(man.name); //结果为hello
changeArray(array);
alert(array[0]); //结果为100
}
test();
</script>

值得一提的是,在Ecmascript 262 3rd规范中有引用类型一说:

The Reference Type
The internal Reference type is not a language data type. It is defined by this specification purely for
expository purposes. An implementation of ECMAScript must behave as if it produced and operated upon
references in the manner described here. However, a value of type Reference is used only as an
intermediate result of expression evaluation and cannot be stored as the value of a variable or property.

且在javascript高级程序设计中,也有说明:

Reference Types
Reference types are commonly referred to as classes, which is to say that when you have a reference
value, you are dealing with an object. The vast number of predefined ECMAScript reference types are
discussed throughout the book. For now, the discussion focuses around the reference types that are
closely related to the primitive types just discussed.
ECMAScript doesn’t actually have classes in the traditional sense. In fact, the word “class” doesn’t
appear in ECMA-262 except to explain that there are no classes. ECMAScript defines “object definitions”
that are logically equivalent to classes in other programming languages. This book chooses to use
the term “class” because it is more familiar to most developers.

当然用引用类型来说明javascript的参数传递的话,javascript确实只有值传递一种,但若把它看作是对象的传递,也可以看作引用传递.因为其符合引用传递的特征.

对值结果传递的补充:

从编译程序的编写者的观点来看,值结果传递要求对运行时栈以及调用序列的基本结构的进行若干个修改。首先,被调用的程序不能释放活动记录,这是因为 复制出的(局部)值还必须对调用程序适用。其次,调用程序必须或是在建立新的活动记录开始之前就将自变量的地址压入到栈中,或是必须从被调用的程序中重新 计算出这些返回的地址。-<程序设计原理>

一个实在参数传递给一个过程时是通过产生一个副本给过程使用,但在过程完成时,过程的副本里的值在调用过程继续执行之前传递给实在参数.
这种情况,称参数是值-结果传递.-<计算机科学概论>

对名字传递的补充:

在调用点上的自变量的文本被看作是它自己右边的函数,每当在被调用的过程的代码中到达相应的参数名时,就要计算它。我们总是在调用程序的环境中计算自变量,而总是在过程的定义环境中执行过程。-<程序设计原理>

另一种是延迟赋值,如
In[10]: = x: = 6+3
系统没有立即给出x的值,只有在下一次调用时,才赋一次值.-<高等数学>