锁定老帖子 主题:一个绝对害了不少人的Java技术问题!
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2004-04-06
在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++中是有明显的区分的(通过*与&) 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2004-04-06
不是call的缘故, 而是 t = t2的缘故
|
|
返回顶楼 | |
发表时间:2004-04-06
JAVA里面的引用实际上就是指针,不象C++中引用与指针是两个概念。
|
|
返回顶楼 | |
发表时间:2004-04-06
Java只有一种参数传递方式,那就是传值。
证明如下: //Test.java class Test { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } //TestTransferParameter.java public class TestTransferParameter{ public static void main(String[] args) { Test a = new Test(); a.setName("a"); Test b = new Test(); b.setName("b"); System.out.println("before swap: " + "a=" + a.getName() + "; b=" + b.getName()); swap(a,b); System.out.println("after swap: " + "a=" + a.getName() + "; b=" + b.getName()); } private static void swap(Test a, Test b) { Test temp; temp = a; a = b; b = temp; System.out.println("swaping: " + "a=" + a.getName() + "; b=" + b.getName()); } } 输出结果: before swap: a=a; b=b swaping: a=b; b=a after swap: a=a; b=b 如果用基本数据类型比如int代替上面的a,b,比如a=100;b=0; 输出结果: before swap: a=100; b=0 swaping: a=0; b=100 after swap: a=100; b=0 现在很清楚了,Java只有一种参数传递方式,那就是传值。 附:《编译原理》中介绍的四种参数传递方式: 1、传地址 call by reference 2、传值 call by value 3、传名 call by name 4、得结果 call by result 以上是个人的一点理解,有不同意见欢迎探讨! |
|
返回顶楼 | |
发表时间:2004-04-06
现在很清楚了,Java只有一种参数传递方式,那就是传值。
--------------------------- 那怎么解释这种情况: public modify(Test t) { t.setName("222") } class Test(){ string name = "111"; public setName...; } main(){ Test test = new Test(); System.out.println(test.getName() ); modify(test); System.out.println(test.getName() ); } 打印的结果是111 222 可见在这里例子中是传引用,不是传值。 从语言设计的角度来说,不可能设计成只能传值。 楼上的和楼主的例子确实有些奇怪。。。。 |
|
返回顶楼 | |
发表时间:2004-04-06
<%! private void modify(Book b);{ System.out.println("### begin modify");; System.out.println("the ref of b is:" + b);; Book book2 = new Book();; book2.setBookName("222");; System.out.println("the ref of book2 is:" + book2);; b = book2; System.out.println("after assign value,the ref of b is:" + b);; System.out.println("b.getName();:" + b.getBookName(););; System.out.println("### end modify");; } %> <% Book book = new Book();; book.setBookName("1111");; System.out.println("--- before modify");; System.out.println("book is:"+book);; System.out.println("bookName is:"+book.getBookName(););; modify(book);; System.out.println("--- after modify");; System.out.println("book is:"+book);; System.out.println("booName is:"+book.getBookName(););; %> 输出结果: --- before modify book is:com.jaqsoft.demo.Book@765f2360 bookName is:1111 ### begin modify the ref of b is:com.jaqsoft.demo.Book@765f2360 the ref of book2 is:com.jaqsoft.demo.Book@77866360 after assign value,the ref of b :com.jaqsoft.demo.Book@77866360 b.getName();:222 ### end modify --- after modify book is:com.jaqsoft.demo.Book@765f2360 booName is:1111 |
|
返回顶楼 | |
发表时间:2004-04-06
从上面的例子很明显的看出,对象调用绝对传递的是对象的引用,而非对象的拷贝!-在book对象传进去之后它的ref值没有改变。
而将新的对象的引用赋值给book,在函数内book的引用确实改变了,所以能打印出改变后的结果。 但是脱离函数之后,book的引用为什么又回到了赋值前的那个呢??? --这才是引入误会的地方,这个地方直接导致了误会:传值。 现在的问题是为什么book的引用在脱离函数后,为什么会回复到以前的值?? 按照常规理解应该是,赋值后,book将一直指向book2所引用的对象,而book以前所指向的对象则列入垃圾收集的范畴。 谁能解释一下这个奇怪的现象?? |
|
返回顶楼 | |
发表时间:2004-04-06
jaqwolf 写道 <%! private void modify(Book b);{ System.out.println("### begin modify");; System.out.println("the ref of b is:" + b);; Book book2 = new Book();; book2.setBookName("222");; System.out.println("the ref of book2 is:" + book2);; b = book2; ———————————————————— 问题出在这。 至于为什么?想想应该不难得出结论。 我是这样理解的。程序里会有对象以及对象的引用。对象就是占用内存比较大的东西,引用就是占用内存比较小的东西,可以看作是C里的指针。Java里的传值实际上是拷贝引用,而不是拷贝对象。 所以不管引用怎么变,只要不调用引用的方法,对象的任何属性都不会变。 |
|
返回顶楼 | |
发表时间:2004-04-06
感觉上是作为参数的句柄在方法内部是受到一定的保护,当直接获得该句柄所指
的内存空间进行操作时能顺利进行,如: public void modify(Object obj);{ Object newobj = new Object();; newobj = obj ; newobj. .....; } 但如果想将参数句柄指向另外一个内存空间的时候,在方法内部的操作结果只在方法内部有效,返回后该句柄还是回到原来所指向的内存空间,如: public void modify(Object obj);{ Object newobj = new Object();; obj = newobj ; obj. .....; } 小弟愚见,希望高手指正 |
|
返回顶楼 | |
发表时间:2004-04-06
引用 Java里的传值实际上是拷贝引用,而不是拷贝对象。
OK,一语中第。 java传递是引用的拷贝,既不是引用本身,更不是对象。 所有的问题都结了。 |
|
返回顶楼 | |