免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: cnflybird
打印 上一主题 下一主题

老题从谈 ---再次让我迷惑 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2007-02-07 15:15 |只看该作者
看来不少同志对这里还有误会,具体说一下吧

java语言里面参数传递全部都是传值的,也就是把实参复制一份出来赋值给形参

大家都知道java数据类型有两类,值类型和引用类型,应该也知道值类型和引用类型都存在什么位置吧?
一般来说简单数据类型变量存放在栈里面,引用类型的变量。。。也是存放在栈里面的,我是说引用!至于对象是放在堆里面的。

例如有一个A类

  1. public class A{
  2.     int i = 10;
  3. }
复制代码

先来创建个对象

  1.   .....
  2.   A a = new A();
  3.   .....
复制代码

new A()的时候堆中产生了一个A类对象,并且有个int型的属性i,其值是10
并且赋值给了一个A类的引用a,也就是引用a指向一个A类对象
再来看个赋值

  1.   ....
  2.   A a1 = a;
  3.   ....
复制代码

把引用a赋值给了引用a1,现在的状况是栈里面有两个A类引用a和a1,他们在栈内的值是相同的,按照C指针的观点来说,a和a1存放的是同一个地址,按照java的说法,a和a1引用到了同一个对象。那么对于a或者a1的操作其实都是操作着同一个对象。例如

  1.   ....
  2.   a.i = 20;
  3. System.out.println(a1.i);  //echo 20
  4.   ....
复制代码


那么,现在再来说参数传递的问题,弄个Test类

  1. public class Test{
  2.     public  static void func(A b){
  3.          b.i = 20;
  4.    }
  5.     public static void main(String[] args){
  6.         A a = new A();
  7.         System.out.println(a.i); // echo 10;
  8.         func(a);  //把a.i属性变成20
  9.         System.out.println(a.i); //echo 20;
  10.    }
  11. }
复制代码

这不是传的引用,或者说传指针嘛?
不!这是一个美丽的误会,事实上是这样的

当调用func(a)方法的时候,a是一个A类对象的引用,它存在于栈中,是把a这个引用的值,也就是栈里面这个值赋值了一份赋值给了形参b,相当于b=a的操作。
所以实际上func方法里面的形参变量b和main方法中的局部变量a是两个栈里面的变量,但是他们引用到了同一个A类对象,所以修改任何一个,另外一个会跟着变动


若说传引用或者传指针也是达到一样的效果。是的,但若传的是指针的话,应该对形式参数赋值也会影响到实际参数(请回忆下C里传地址的有关知识),可事实并非这样,在方法内给形参赋值只改变了方形参的值并不会改变实参的值,原因也就是形参跟实参实际上是两个引用,只不过当把实参的值传递过来的时候两个引用的值相等了,也就是引用到了同一个对象。而传指针,应该是形参指向实参,那b里面存放的就成了a这个引用的地址了。

所以,java的参数传递全部都是传值的,而不是传址的。
传值是把实参的值取出来赋值给形参,传址是把实参的地址取出来赋值给形参。
取出来的值是栈里面的值,对于简单变量那就是变量值,而对于引用类型而言,那就是这个对象的引用。引用的值应该基本可以看做是对象的地址了。

其实perryhg版主的帖子写的很明白了。。。。

另外,对于String的问题,顺便说一句,String类是个不可变类,它的对象一旦创建就不会在改变。
说String特殊,并不是为了char*这样的用法作为基本数据类型的补充,而是在于它创建对象的赋值方式。一般类对象需要用new操作符创建,而String除了new之外,可以直接赋值,也就是说java承认你在源代码中写一对双引号就是一个String类型的对象了。也就是说

  1.   String s = "abc"; //这里有个字符串对象“abc”,s是它的引用
  2. s = "bcd"; //这里给s引用赋了个新对象“bcd”,现在实际上有两个String对象"abc"和"bcd",不是说abc这个对象改变成了"bcd"的样子
复制代码


那么楼主里面

  1.   public static void change(String str)
  2.     {
  3.         str ="new";
  4.     }
复制代码


实际上就是给str这个形参赋了个新的字符串对象。这跟我在15楼给的例子其实一个样子的

  1.     public static void func(A a){
  2.         a = new A();
  3.         a.i = 15;
  4.    }
复制代码

根本就是给形参赋了新值,而java参数传递是传值的。所以不会把实参改了,最后怎么调用change也只会打印出来传递之前的实参的值,因为传进去之后,形参和实参指向了两个对象了,改形参对象,对实参引用到的对象没作用

upstorm,呵呵,你是不会用错,不过概念上有错误

论坛徽章:
0
22 [报告]
发表于 2007-02-07 16:22 |只看该作者
取出来的值是栈里面的值,对于简单变量那就是变量值,而对于引用类型而言,那就是这个对象的引用。引用的值应该基本可以看做是对象的地址了。
==========================================================
这是你写的吧,和我说的有区别吗?
你自己都说了对于引用类型而言,那就是这个对象的引用,何必又勉强加上“引用的值应该基本可以看做是对象的地址了”,既然是值了,怎么又说可以看成地址,按你的逻辑,一切都是值好了,我当然无话可说,但是你自己看看C里面值和地址是严格区分的,“引用的值应该基本可以看做是对象的地址了”---你自己反省吧

论坛徽章:
0
23 [报告]
发表于 2007-02-07 16:27 |只看该作者
其实你已经很清楚这方面的理论了,我觉得我们就是在传递了一个地址的时候,叫它是地址还是值,我们在撤来撤去。

论坛徽章:
0
24 [报告]
发表于 2007-02-07 16:33 |只看该作者
呵呵,关键是,传址和传值的概念不一样啊

还一点就是,引用和对象不是一回事儿,传值都是传的栈里的值,而传址是传变量的地址

把引用的地址传进去才算传址,把对象的地址传进去其实是传的栈里(也就是引用)的值

~~

嗯,不管传什么样的类型参数进去,遵守的法则是一样的

[ 本帖最后由 艾斯尼勒 于 2007-2-7 16:36 编辑 ]

论坛徽章:
0
25 [报告]
发表于 2007-02-07 16:41 |只看该作者
把对象的地址传进去其实是传的栈里(也就是引用)的值
==================================

我明白你的意思,你认为真实的数据地址才是真正的地址,而类的地址并不是真正的数据地址,仅仅是对对象的一个代表,并不是真正的地址,哎,也是,我是从c++进入java的,const A* a,a--就是一个指针(虽然c++里面a也是对一个类的表示,并不是一个真正的数据地址),这样比较好理解些,算了,你的意思我也明白来,其实理解都没有错,就是一个称呼罢了

论坛徽章:
0
26 [报告]
发表于 2007-02-07 17:15 |只看该作者
传值都是传的栈里的值,而传址是传变量的地址
===========================================

不好意思,我说一句
我好像知道了,你认为是“值”的根源在上面的这句话

我只是想说一句话:栈里面:有地址,也有值。

论坛徽章:
0
27 [报告]
发表于 2007-02-07 17:33 |只看该作者
呵呵,讨论深了

论坛徽章:
0
28 [报告]
发表于 2007-02-09 23:35 |只看该作者
原帖由 upstorm 于 2007-2-7 14:05 发表


其实一般java传递的基本都是指针,string算是一个特例吧
你传递hashtable和类试试就知道了,比如你传递一个类进去,修改了它的某个类字段的值,函数结束之后,类字段的值不会因为函数退出而还原的


java里面所有object参数传递的原则是一样的,你把String理解为特例,说明你的理解还很肤浅,你只理解了“指针”的概念,但是并没有更深入思考“指针的指针”。为什么java的文档里面告诉你java的参数传递是传“值”的是有道理的,只是你还没参透而已,继续学习吧!另外,请你说话礼貌一点,学术讨论没必要那么激动。

论坛徽章:
0
29 [报告]
发表于 2007-02-10 13:44 |只看该作者
不要拿String来做例子,它和那些Wrapper类都是特殊的,称为不变类。
看一下它们的Source Code就能知道,它们在实例化后是不能改变值的。
所有的Object都是传递Ref的。

论坛徽章:
0
30 [报告]
发表于 2007-02-11 12:25 |只看该作者
原帖由 perryhg 于 2007-2-9 23:35 发表


java里面所有object参数传递的原则是一样的,你把String理解为特例,说明你的理解还很肤浅,你只理解了“指针”的概念,但是并没有更深入思考“指针的指针”。为什么java的文档里面告诉你java的参数传递是传“ ...


String类上下的朋友都说了,实现的确是不同,我指特殊,也并没有指明它的参数传递原则特殊(我没有去看java的源码,因为java的上层应该的概念太多了,上层的开发封装也特别多,以后有时间了也去看看java的源码和虚拟机)只是估计用了一个特殊的机制去做这件事情(相信楼上说的:它和那些Wrapper类都是特殊的,称为不变类)。

所谓指针/指针的指针,宏观都是指针。有必要去细化吗?如果你觉得要细化,就请细化给我看啊,不要搬出一个文档来敷衍。

如果说我没有参透,你呢?你上面讲了那么多,又讲了什么实际的东西?我只看见你搬出一个java文档,说了一些莫名的东西之后,归结一个继续学习,说话不要那么激动。

学术是大家一块讨论,一块提高,摆出事实,讲出道理。而不是随便放出一个卫星结论
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP