辞职专心找工作了。没事干就开始啃那本买了一年多都还没看的Thinking In Java。巩固巩固基础吧
Java传值还是传引用好像自Java出现后就一直存在争论,大家各持己见。这里阐述下自己的理解,算是对Thinking in Java的一个读书笔记。
一.预备知识
在Thinking in Java的第二章里,提到了Java将对象存放到了哪里。这里主要看栈和堆。
看下面几行代码的区别。
int i = 1;
String str = new String("Hello");
从第二行代码里又可以引申如一个经典的面试题,这里创建了几个String对象。这里不做讨论。
大家都知道左边的是引用,指向了右边的实际的值。但是在Java里面这两段有区别吗?看图。
从图上可以看出,栈里的每个值又可以看成是一个个的键值对。
对于
int i = 1;
来说,键就是变量i,而值就是1。
而对于
String str = new String("Hello");
来说,键是变量str,而值是new String("Hello");在堆里的地址。(在Java中所有new出来的东东都在堆里面)
二.传值还是传引用?
好,知道了上面的区别,对于传值和传引用的理解就很有帮助了。
看下面的代码。
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";
}