黑马程序员技术交流社区

标题: 关于值传递,引用传递的那些事 [打印本页]

作者: Jaybor    时间: 2015-5-27 22:28
标题: 关于值传递,引用传递的那些事

堆栈和堆:堆栈存储速度仅次于寄存器,明显快于内存堆,存储对象的过称为:当需要开辟内存的时候指针下移,当需要释放空间的时候指针上移。然而这种方法要求明确对象大小和生命周期,所以缺乏灵活性。在Java中堆栈主要用于存储引用和基本数据类型的数据。
而堆采用的是动态开辟内存的方式,使用较为灵活,但是由于需要在程序运行期间存储对象所以会导致程序运行速度下降。在Java中堆主要用于存储new出来的对象。
1.基本数据类型
如果我们定义了一个int a=3;程序会在栈中开辟一块内存用于存储a和值3;如果这时又定义了int b=3;那么a和b此时会指向栈中同一个对象。
2.普通引用
如果我们定义了一个ArrayList list=new ArrayList();list引用就会存放在栈中,而list指向的对象就会存在于堆中。
3.字符串
当我们定义了一个String s="haha";s引用存在于栈中,s指向的对象却不在堆中而是存在与一个叫“常量池”的地方。同样的如果我们定义了一个final int MAX_VALUE=20;该变量也会被放入常量池。
而如果用String s2=new String("hehe")方法创建字符串对象;那么程序就会在堆中创造一个相应的对象,同时,它还会在常量池创建一个字符串(前提是常量池中并不存在该对象)。




下面是一个栗子:
  1. public class Test {
  2.         public static void main(String[] args) {
  3.                 String str=new String("abc");//对象存在与堆中
  4.                 char[] ch={'z','w','q'};
  5.                 Test test=new Test();
  6.                 test.change(str, ch);//操作str和ch
  7.                 System.out.println(str+","+ch[0]);
  8.         }
  9.        
  10.         public void change(String str,char[] ch){
  11.                 str="new value";
  12.                 ch[0]='y';
  13.         }
  14. }
复制代码

输出的结果为abc,y;
问题:为什么在方法里面str指向的对象改成了“new value”,那么为什么输出的结果是“abc”呢?
分析:这里的str虽然是一个引用,然而它所指向的对象却是一个字符串(常量)。而在方法里面str指向的对象发生了改变,但是方法一旦调用结束引用就会消失,而原来的str引用所指向的对象"abc"并没有发生变化,所以打印出来的仍然是"abc";
这里有一个作用域的概念:一旦change()方法调用结束引用就被销毁了然而“new value”仍然存在于常量池中。

对比老师讲过的引用传递的例:
  1. public class Test {
  2.         public static void main(String[] args) {
  3.                 ArrayList list=new ArrayList();
  4.                 list.add(0);
  5.                 list.add(1);
  6.                 list.add(2);
  7.                 change(list);//传递的引用的值
  8.                 System.out.println(list);
  9.         }
  10.        
  11.         public static void change(ArrayList list){
  12.                 ArrayList list2=list;
  13.                 list2.remove(0);//list指向的对象已经发生改变了
  14.         }
  15. }
复制代码
打印结果:【1,2】
这个例子和上面的例子的区别在于list指向的对象在方法中被改变,而上面的例子中引用str指向的对象根本没变化。
所以所谓引用传递和普通数值传递的区别在于能否改变所指向的对象。


欢迎拍砖,始终相信理越辩越明~~~~~~





作者: 仅此一抹心醉    时间: 2015-5-27 22:33
:lol好吧  总结的很好·····学习一下
作者: rexih    时间: 2015-5-27 22:43
然而java并没有引用传递,只有值传递

例1中传递进change的是在main中的对象变量str,而change中的str复制了前者的引用,同样指向相同的地址,在change中,change的str又指向了新的对象。然而在函数运行结束后,change的str消亡,main中的str仍然指向原来的对象。
而对于数组,将,main中数组对象变量传给change,change中的数组对象变量和main中的指向的是同一个数组,在change中修改[0]中的值,致使main和change中的ch所共同指向的数组的值改变。这种改变即使change结束,change中的ch消亡也没有关系,因为其所指向的对象的状态已被改变。
作者: Jaybor    时间: 2015-5-27 22:47
本帖最后由 Jaybor 于 2015-5-27 22:49 编辑
rexih 发表于 2015-5-27 22:43
然而java并没有引用传递,只有值传递

例1中传递进change的是在main中的对象变量str,而change中的str复制 ...

java中引用传递的的确是值;然后你的分析其实可以概括为:方法改变了ch所指向的对象本身,却没有改变str指向的对象;
作者: Lucus    时间: 2015-5-27 23:01
学习了,关于常量池还不怎么明白,感谢分享!!
作者: rexih    时间: 2015-5-27 23:11
Jaybor 发表于 2015-5-27 22:47
java中引用传递的的确是值;然后你的分析其实可以概括为:方法改变了ch所指向的对象本身,却没有改变str指 ...

引用传递是直接把变量的地址给方法,在方法中使用引用和在invoker中的是相同的对象。然而在java中

只有 值传递,

即你在调用方法时写入参数的那个对象,在方法中,方法是值传递,复制了那个对象的一些状态,创建了一个副本
作者: 卡布    时间: 2015-5-27 23:31
学习了~
作者: 夜愿Relax    时间: 2015-5-27 23:43
新手学习学习
作者: 南方小道士    时间: 2015-5-27 23:53
路过学习了




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2