前言
参数传递的问题从C语言开始就一直追随我们,最近本人在最准备校招面试,发现他还是如蛆附骨,如影随形。所以我们有必要和他一决高下了。
参数传递在我学习C语言的时候知道了两种,一种是传值,一种是传地址(其实仔细思考都是在传递值,只不过传地址是传递指针的值)。如果想通过函数改变参数本身,就需要传地址才能修改。后来学习了C++,知道C++为了减少指针的操作,使用引用来达到相同的效果。
这样就有了两种参数调用方法,一种是按值调用,一种是按引用调用,当然我在书上还看到了一种,那就是按名调用(古老的高级语言Algol曾经使用这种方法,但是在今天这种传递方式已经成为了过去式了)
Java方法参数传递
上边说了三种调用方法,但是一定要记住,Java只有一种调用方式,就是按值调用。
然后我们针对传递基本类型和非基本类型来进行讨论:
基本类型调用:
这个其实大家都不陌生,如果传递基本类型的话,方法得到的值将是基本类型的拷贝,那么无论执行什么样的操作都不会对原始值造成影响。
因为原始值和拷贝后的值不在一块内存区域中,所以各自执行操作都不会对对方的值造成影响。
非基本类型调用:
非基本类型也是按值调用,可能有些同学会有疑问,因为不是说好的传递非基本类型可以对他的内容进行修改吗?那不就是按引用传递吗?比如在下边的程序中:
public class Employee {
int a = 3;
public static void main(String[] args) {
Employee x = new Employee();
System.out.println(x.a);
tripleA(x);
System.out.println(x.a);
}
public static void tripleA(Employee e) {
e.a = e.a * 3;
}
}
输出结果为:
3
9
但是实际上他的内部操作是这样的:
首先 Employee x = new Employee(); 程序申请一块内存空间存储 Employee 对象,然后令x指向它。
然后调用tripleA() 将x传递给函数,此时e是x的一份拷贝,也就是引用的拷贝,这时他们两个都指向相同的Employee对象,所以当函数改变e.a的值的时候,才可以真正改变x.a的值。
可以结合图示查看分析这个过程:
所以此时函数才可以改变x.a的值。
知识进阶
讲了这么多学没学会实践一下最重要(答案在解析后边,做完之后再看答案哦)
例题:
检查程序,是否存在问题,如果存在指出问题所在,如果不存在,说明输出结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
A.test okandabc
B.test okandgbc
C.goodandabc
D.goodandgbc
解析:
在调用change方法之前,我们的内存里的关系是这样的:
然后我们调用change方法,传入参数之后,在未执行change方法内的任何语句之前,内存里的关系是:
这一步也就是我们前边讲的,参数传递之后会将引用拷贝一份作为方法内的局部变量,此时他们两两指向相同的对象。
现在需要知道的是当使用""双引号为String类型赋值的过程类似于任意类 new Object()的过程,也就是重新让这个变量指向了一个新的对象(当然new String() 和 直接使用双引号赋值还是有区别的,而且也不简单,但是不是我们研究的重点,所以不去讨论,只是做一个简化)。而ch修改了指向对象的第一个元素,所以接下来,内存中的关系就会发生微妙的变化。
说到这里,我想大家基本上也知道结果是什么了,change方法中的str指向了新的对象,并没有影响到main方法中str实际指向的对象,change方法中的ch改变了指向对象中的内容,影响到了main方法中ch指向的对象,所以输出结果就是goodandgbc.
正确答案:D
如果能将这个过程全部理解,那么基本上在参数传递上就入门不少啦,上边的例题是网易的一道招聘笔试题。
如有错误,欢迎指摘。