java参数传值:Java参数传值还是传引用来源: 发布时间:星期四, 2009年2月12日 浏览:200次 评论:0
这是个老生常谈问题了引起过无数争论但可以说直没有个令人满意回答 有些人非要故弄玄虚把传引用说成是栈里面放是引用值说只有传值没有传引用那看看这句经典名言吧: O'Reilly's Java in a Nutshell by David Flanagan (see Resources) puts it best: "Java manipulates objects 'by reference,' but it passes object references to methods 'by value.'" 从这里也可以看到David 也没那么生硬不过是看你从哪个角度来认识这个问题如果大家习惯c那种传参时理解方式为何不能这么比较呢? 有人已经整理总结过: 参见 看到大家在看完我转载Java 应用中按值传递语义反倒引起很多争论和导致些人越来越糊涂了因此有必要再详细谈谈我对这个理解了 以下摘自原文: 节选理解参数是按值而不是按引用传递介绍说明 Java 应用有且仅有种参数传递机制即按值传递写它是为了揭穿普遍存在种神话即认为 Java 应用按引用传递参数以避免因依赖“按引用传递”这行为而导致常见编程 对此节选某些反馈意见认为我把这问题搞糊涂了或者将它完全搞错了许多区别意我读者用 C 语言作为例子因此在此栏目中我将使用 C 和 Java 应用进步阐明些事实 要点 读完所有评论以后问题终于明白了至少在个主要问题上产生了混淆某些评论认为我节选是错对象是按引用传递对象确实是按引用传递;节选和这没有冲突节选中说所有参数都是按值 -- 另个参数 -- 传递下面说法是正确:在 Java 应用中永远不会传递对象而只传递对象引用因此是按引用传递对象但重要是要区分参数是如何传递这才是该节选意图Java 应用按引用传递对象这事实并不意味着 Java 应用按引用传递参数参数可以是对象引用而 Java 应用是按值传递对象引用 C 和 Java 应用中参数传递 Java 应用中变量可以为以下两种类型的:引用类型或基本类型当作为参数传递给个思路方法时处理这两种类型方式是相同两种类型都是按值传递;没有种按引用传递这是个重要特性正如随后代码举例所示那样 在继续讨论的前定义按值传递和按引用传递这两个术语是重要按值传递意味着当将个参数传递给个时接收是原始值个副本因此如果修改了该参数仅改变副本而原始值保持不变按引用传递意味着当将个参数传递给个时接收是原始值内存地址而不是值副本因此如果修改了该参数代码中原始值也随的改变 上面这些是很重要请大家注意以下几点结论这些都是我认为上面文章中精华和最终结论: 1、对象是按引用传递 2、Java 应用有且仅有种参数传递机制即按值传递 3、按值传递意味着当将个参数传递给个时接收是原始值个副本 4、按引用传递意味着当将个参数传递给个时接收是原始值内存地址而不是值副本 首先我们来看看第点:对象是按引用传递 确实这点我想大家没有任何疑问例如: Test01 { public void (String args) { StringBuffer s= StringBuffer("good"); StringBuffer s2=s; s2.append(" afternoon."); .out.prln(s); } } 对象s和s2指向是内存中同个地址因此指向也是同个对象 如何解释“对象是按引用传递”呢? 这里意思是进行对象赋值操作是传递是对象引用因此对象是按引用传递有问题吗? 运行输出是: good afternoon. 这介绍说明s2和s是同个对象 这里有点要澄清是这里传对象其实也是传值对象就是个指针这个赋值是指针的间赋值因此在java中就将它说成了传引用(引用是什么?不就是地址吗?地址是什么不过就是个整数值) 再看看下面例子: Test02 { public void (String args) { i=5; i2=i; i2=6; .out.prln(i); } } 结果是什么?5!!! 这介绍说明什么原始数据类型是按值传递这个按值传递也是指是进行赋值时行为 下个问题:Java 应用有且仅有种参数传递机制即按值传递 Test03 { public void (String args) { StringBuffer s= StringBuffer("good"); StringBuffer s2= StringBuffer("bad"); test(s,s2); .out.prln(s);//9 .out.prln(s2);//10 } void test(StringBuffer s,StringBuffer s2) { .out.prln(s);//1 .out.prln(s2);//2 s2=s;//3 s= StringBuffer("");//4 .out.prln(s);//5 .out.prln(s2);//6 s.append("hah");//7 s2.append("hah");//8 } } 输出是: good bad good goodhah bad 为什么输出是这样? 这里需要强调是“参数传递机制”它是和赋值语句时传递机制区别 我们看到1,2处输出和我们预计是完全匹配 3将s2指向s4将s指向个新对象 因此5输出打印是新创建对象内容而6打印原来s内容 7和8两个地方修改对象内容但是9和10输出为什么是那样呢? Java 应用有且仅有种参数传递机制即按值传递 至此我想整理总结下我对这个问题最后看法和我认为可以帮助大家理解种思路方法: 我们可以将java中对象理解为c/c中指针 例如在c/c中: *p; pr(p);//1 *p=5; pr(*p);//2 1打印结果是什么个16进制地址2打印结果是什么?5也就是指针指向内容 即使在c/c中这个指针其实也是个32位整数我们可以理解我个long型值 而在java中个对象s是什么同样也是个指针也是个型整数(对于JVM而言)我们在直接使用(即s2=s这样情况但是对于.out.pr(s)这种情况例外它实际上被转换为.out.pr(s.toString))对象时它是个整数这个可以同时解释赋值传引用和传参数时传值(在这两种情况下都是直接使用)而我们在s.XXX这样情况下时s其实就是c/c中*s这样使用了这种在区别使用情况下出现区别结果是java为我们做种简化但是对于c/c员可能是种误导java中有很多中这种根据上下文进行自动识别和处理情况下面是个有点极端情况: t { public String t="t"; public void (String args) { t t = t; t.t; } void t { .out.prln(t); } } (有关根据上下文自动识别内容有兴趣人以后可以看看我们翻译java规则) 呵呵这篇介绍说明可能会让些人更混乱了但是既然写出来了就贴出来吧不要骂我啊 1、对象是按引用传递 2、Java 应用有且仅有种参数传递机制即按值传递 3、按值传递意味着当将个参数传递给个时接收是原始值个副本 4、按引用传递意味着当将个参数传递给个时接收是原始值内存地址而不是值副本 写没错但是文字太多第 2条就已经把人弄糊涂了得仔细看完4条才清楚而且对String类型疑惑没有解决 这么简单事情何必这么绕呢?为啥没人跟c过不去偏要跟Java来劲? 3句话整理总结下: 1.对象就是传引用 2.原始类型就是传值 3.String类型没有提供自身修改每次操作都是新生成个String对象所以要特殊对待可以认为是传值 1
相关文章读者评论
发表评论 |