<script type="text/javascript"> document.body.oncopy = function() { if (window.clipboardData) { setTimeout(function() { var text = clipboardData.getData("text"); if (text && text.length>300) { text = text + "/r/n/n本文来自CSDN博客,转载请标明出处:" + location.href; clipboardData.setData("text", text); } }, 100); } } </script> <script type="text/javascript">function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>
时间: 2004-4-06 13:18:27 标题: 一个绝对害了不少人的Java技术问题! | |
|
我不记得自己是怎么学到的,但是我相信绝大部分从事java学习Java的人都一直这么以为一个小的技术问题: 在Java中方法参数的传递,对象是传递引用,基本数据类型是传递值。而且一直一来都似乎没有人提出过疑问。 直到最近,我在为公司基本Java开发人员编写考试试卷的时候,我才发现,这错了!在方法中,Java语言中对象传递的是地址,而不是引用,这两个概念是有非常大的差别的,我相信熟悉c++的人都应该知道。 例如下面:假设对象Test有name的属性。 public void call(Test t) { Test t2 = new Test(); t2.setName("cba'); t.setName("abc"); t = t2 ; } public static void main(String[] arg) { Test obj = new Test(); call (obj) ; System.out.println("obj"+obj.getName()); } 这 个时候,你们可以发现,打印出来的是"abc" ,而不是"cba",原因是这样的,在这次调用中,等于声明了两个变量obj , t,它们指向的是同一个地址,调用call方法,只是将obj指向的地址传递给了t,而obj本身并没有传递过去(也就是没有传递引用),当你重新赋值的 时候(也就是将对象引用指向其他存储空间),等于只影响了t,而没有影响obj。 这样的传递方式只能称之为址传递,或者是引用对象传递,而不嫩说是传递引用或者引用传递。 我不知道这究竟属于翻译的错误,还是我们理解的错误。但是这样的问题在c++中是有明显的区分的(通过*与&) |
时间: 2004-4-06 21:07:10 标题: | |
|
1、首先弄清楚一个问题:Java有没有指针? 对于 在C和C++里头曾经给我们带来欢乐同时也有无限痛苦的指针,很多人宁愿它再也不要出现在Java里头。然而事实上,Java是有指针的,Java中每个 对象(除基本数据类型以外)的标识符都属于指针的一种。但它们的使用受到了严格的限制和防范,在<Thinking in Java>一书中称它们为句柄。 2、传递句柄 将句柄传递进入一个方法时,指向的仍然是相同的对象。 public class Testit { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public static void main(String[] args) { Testit a = new Testit(); a.setName("a"); Testit b = new Testit(); b.setName("b"); System.out.println("before swap: " + "a=" + a + " name: " + a.getName()); swap(a,b); } private static void swap(Testit swap1, Testit swap2) { System.out.println("swaping: " + "a= " + swap1 + " name: " + swap1.getName()); Testit temp; temp = swap1; swap1 = swap2; swap2 = temp; } } 输出结果: before swap: a=com.lib.Testit@16930e2 name: a swaping: a= com.lib.Testit@16930e2 name: a 3、一个句柄的传递会使调用者的对象发生意外的改变。 public class Testit { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public static void main(String[] args) { Testit a = new Testit(); a.setName("a"); Testit b = new Testit(); b.setName("b"); System.out.println("before swap: " + "a=" + a + " name: " + a.getName()); swap(a,b); System.out.println("after swap: " + "a=" + a + " name: " + a.getName()); } private static void swap(Testit swap1, Testit swap2) { Testit temp; temp = swap1; swap1 = swap2; swap2 = temp; swap1.setName("a's name"); swap2.setName("b's name"); } } 输出结果: before swap: a=com.lib.Testit@16930e2 name: a after swap: a=com.lib.Testit@16930e2 name: b's name 我们看到,a依旧是原来那个a,但name却不是原来那个name了! 在swap()方法中,swap1和swap2互相换过来了,这个时候swap2指向的是a,所以在setName()的时候改变的是a的name,而不是b的name。 为什么会这样呢? liang_chen兄高见:Java里的传值实际上是拷贝引用,而不是拷贝对象。 总结: 1:对于值类型的参数来说,传递的是值的拷贝. 2:对于引用类型的参数来说,传递的是引用本身的拷贝. 所以关键要看你如何理解传值中的这个“值”了。 |
时间: 2004-4-06 22:56:27 标题: 哈哈,好热闹 | |
|
没有想到这个问题引起这么多朋友的共鸣, 楼上有位仁兄关于“java传递是引用的拷贝,既不是引用本身,更不是对象。”这句话说得非常好!可惜现今发现的任何一本书都没有说明。 当然这个传递是对象,而不是简单数据类型,简单数据类型还是传递值的拷贝的。 楼上还有一位仁兄拿出了编译原理,这正是问题的所在,传递地址、传递引用、传递结果(也就是值拷贝),这里所说的传递引用和传递地址有什么差别? 楼上的liang_chen的理解非常好,我直到前一段才真正发现(在我身边差不多都不清楚这个问题),三年多的java分析设计开发经验,到今天才理解透这样一个基础的问题,我真是汗颜。:( 所以,其他还在争论不清楚的各位朋友,一定要认真地学习java,不能随便说自己精通的,哈哈,大家多加探讨,继续共同提高。 |
时间: 2004-11-10 12:38:00 标题: 句柄与指针--讨论凤舞凰扬的问题 | |
|
凤舞凰扬的原帖子实在太长了,在这里新开一个帖子讨论这个问题。 我认为,java并没有c++中指针、地址的概念,它只有句柄(handler)的概念。还以凤舞凰扬的两个方法为例: public void call(Test t) { Test t2 = new Test(); t2.setName("cba'); t.setName("abc"); t = t2 ; } public static void main(String[] arg) { Test obj = new Test(); call (obj) ; System.out.println("obj"+obj.getName()); } 总共构建了两个Test对象,假设称main方法构建的对象为“对象1”,call方法构建的对象为“对象2”, 在main方法中,变量obj获得了“对象1”的句柄, 在参数传递中,变量obj把这个句柄传递给变量t, 在call方法中,变量t首先改变了“对象1”的属性,然后变量t又获得了“对象2”的句柄(但obj仍然是“对象1”的句柄), call方法返回后,由于“对象2”失去了唯一的句柄,不可避免的进入垃圾收集器的视线。而obj仍然是“对象1”的句柄,由于“对象1”的属性已经被重新设置,所以我们可以看到打印出来的结果是“abc”。 所以我认为以下论断是没有问题的: “在Java中方法参数的传递,对象是传递引用,基本数据类型是传递值。” |