Ref: http://ivan-pig.iteye.com/blog/422891
一.预备知识
在Thinking in Java的第二章里,提到了Java将对象存放到了哪里。这里主要看栈和堆。
看下面几行代码的区别。
Java代码
int i = 1; String str = new String("Hello");
从第二行代码里又可以引申如一个经典的面试题,这里创建了几个String对象。这里不做讨论。
大家都知道左边的是引用,指向了右边的实际的值。但是在Java里面这两段有区别吗?看图。
从图上可以看出,栈里的每个值又可以看成是一个个的键值对。
对于
Java代码
- int i = 1;
来说,键就是变量i,而值就是1。
而对于
Java代码
- String str = new String("Hello");
来说,键是变量str,而值是new String("Hello");在堆里的地址。(在Java中所有new出来的东东都在堆里面)
二.传值还是传引用?
好,知道了上面的区别,对于传值和传引用的理解就很有帮助了。
看下面的代码。
Java代码
public class Change { public void change(int i){ i = 2; } public void change(String str){ str = "Ivan"; } public void change(StringBuffer str){ str.append(" World"); }
那么将上面的i和str传入如下的三个方法中是否有作用呢?(这里添加了一个StringBuffer,是因为你无法改变String)
再来看下Java中的方法如何执行的。在Thinking in Java第七章中,提到了一点。方法的执行是将参数压入栈中,跳至方法代码处执行方法,然后跳回并清理栈中的参数,处理返回值。从这里可以知道,方法的参数在栈里面也有对应的存储空间,而值就是传入的i和str在栈中所对应的值。也就是说,是i和str的一个拷贝。
那么来看上面的三个方法。
对于第一个方法,从上面可以知道,这里的i和原来的i已经不是同一个i了,所以这里操作的是完全不同的东东。
第二个方法和第一个相似,根据前面知道,这里的str持有的是指向"Hello"的引用。但是这里直接将这个引用改成了指向"Ivan"的,原来的str还是指向"Hello",对原来的str没有一点影响。
第三个方法是是直接操作了str所指向的那个"Hello",因为原来的str指向同样的"Hello",所以这就会改变原来str的值了。
三.总结
从上面可以知道,Java是将栈里的值拷贝了一份作为参数传到了方法里面。对于基本类型就是传的值了,而对于对象类型就是引用了。不管传的是值还是引用,都是栈里的拷贝。记住这一点应该就不会再有什么疑问了
四.关于数组
继续看Thinking in Java,关于数组一节的介绍,有这么一句。无论使用的是哪种类型的数组,数组标示符其实只是一个引用,指向在堆中创建的一个真实对象,这个(数组)对象用以保存指向其他对象的引用。
再结合上面的内容,下面两个方法能否改变值应该能知道吧
public void change(int[] i){ i[0]=1; } public void change(String[] str){ str[0]="Ivan"; }