黑马程序员技术交流社区

标题: 关于类的传递问题。 [打印本页]

作者: xieshuhua    时间: 2012-5-28 21:33
标题: 关于类的传递问题。
本帖最后由 谢述华 于 2012-5-29 10:45 编辑

如下面代码和图所示:
为什么设置s1会导致s的值发生变化,设置i1的值不会导致i的值变化。第一种情况感觉太诡异了,请高手帮忙指点下啊,谢谢啦。
5.29八点又重新修改了下,增加了数组。以供大家讨论共同提高~~
10点再次修改,增加字符串。
  1. class Res{
  2.         String name="wang";
  3.         String sex="nv";
  4.         boolean flag = false ;
  5. }
  6. class Input{
  7.         private Res s1=new Res();
  8.         int i1;
  9.         int [] j1;
  10.         String t1;
  11.          Input(Res s,int i,int [] j,String t){
  12.           s1 = s;
  13.           i1=i;
  14.           j1=j;
  15.           t1=t;
  16.         }
  17.         public void set(){
  18.           s1.name = "lily";
  19.           s1.sex = "girl";
  20.           i1=3;
  21.           j1[0]=3;
  22.           t1="buxie";
  23.         }
  24. }
  25. class cw{
  26.         public static void main(String[] args) {
  27.                 Res s = new Res();
  28.                 int i=0;
  29.                 int []j={0};
  30.                 String t="xie";
  31.                 new Input(s,i,j,t).set();
  32.                 System.out.println(s.name+"."+s.sex+"."+i+"."+j[0]+"."+t);
  33.        }
  34. }
复制代码

运行效果.png (1.95 KB, 下载次数: 59)

运行效果.png

作者: 秦冲    时间: 2012-5-28 21:41
你太大意了,你在最后的输出语句中访问的 i 就是 mian方法中前面声明的 i,并不是s.i
作者: 付信榕    时间: 2012-5-28 21:47
因为s1和s指向的是同一片内存,见图可知如何变化。

未命名.PNG (21.24 KB, 下载次数: 47)

解释图

解释图

作者: 李哲    时间: 2012-5-28 21:48
new Input(s,i)里面的s1和外面的Res s = new Res();中的s指向的是同一个实例对象。
i则只是局部变量,没什么可说。

楼主这个加深基础知识学习的例子,很好。

作者: 杨永峰    时间: 2012-5-28 22:10
Input(Res s,int i){    /* s 是指向Res类新建的对象的一个引用,作为参数传递过来,这里的 Res s 是在Input方法所属的内存中又新建了一个Res类的对象的引用 变量,main方法中内存中的 s 将引用传给 Input 所属内存的s,然后这个s又将引用传递给了s1,所以s1仍然指向main 中创建的那个对象。 */
s1 = s;                  /* int 变量在传递过程中,传递的是其指向的值:0;main所属内存中的 i 将其值赋值给 参数中的 i , 参数中的 i 是在input所属内存中新建的          变量。i1又指向了值 0;*/
i1=i;
}
作者: xieshuhua    时间: 2012-5-28 22:17
秦冲 发表于 2012-5-28 21:41
你太大意了,你在最后的输出语句中访问的 i 就是 mian方法中前面声明的 i,并不是s.i ...

我没有大意,i只是起辅助说明的作用。我是第一个搞不清楚为什么。
作者: xieshuhua    时间: 2012-5-28 22:23
付信榕 发表于 2012-5-28 21:47
因为s1和s指向的是同一片内存,见图可知如何变化。

07.private Res s1=new Res();
改了第七行,执行的效果不变。。。
作者: xieshuhua    时间: 2012-5-28 22:24
李哲 发表于 2012-5-28 21:48
new Input(s,i)里面的s1和外面的Res s = new Res();中的s指向的是同一个实例对象。
i则只是局部变量,没什 ...

这里面应该还包含着一堆的知识吧,不是2句就能说完的吧。求教。。。。
作者: xieshuhua    时间: 2012-5-28 22:26
杨永峰 发表于 2012-5-28 22:10
Input(Res s,int i){    /* s 是指向Res类新建的对象的一个引用,作为参数传递过来,这里的 Res s 是在Inpu ...

你的意思是:s只是一个指向一个地址的指针。老师貌似都没有说过,那本书上有这方面的介绍呀。
一般我们都是把它当做一个对象。。。s1又是一个新的对象,一般的理解,最少地址是不同的。
作者: 杨永峰    时间: 2012-5-28 22:41
本帖最后由 杨永峰 于 2012-5-28 22:51 编辑
谢述华 发表于 2012-5-28 22:26
你的意思是:s只是一个指向一个地址的指针。老师貌似都没有说过,那本书上有这方面的介绍呀。
一般我们都 ...

s 一般在占栈内存中,存放对象的地址值,虽然java中没有指针的概念,但是这个可以理解为指针。最后main中的s 和 Input中的 s1 都指向了main中新建的对象,多对一的指向是允许的。你可以尝试打印 s1 看看。
我觉得要是比较深入的理解,需要熟悉java 的内存分配、管理,参数传递过程中方法体和调用对象内存及内存中的一些实例的变化。这应该属于JVM的范畴了吧。

作者: xieshuhua    时间: 2012-5-28 22:44
杨永峰 发表于 2012-5-28 22:41
s 一般在占栈内存中,存放对象的地址值,虽然java中没有指针的概念,但是这个可以理解为指针。最后main中 ...

正在学习JVM中,刚看了20多页。。。觉得非常非常重要。
作者: 袁梦希    时间: 2012-5-28 23:14
这是关于值传递和对象传递的问题,
说白了就一句话:
当基本类型进行传递的时候是值传递,传递的大白话也就是传参数,值不会改变,保留原有值。
当类类型或者说是引用类型传递的时候叫做,对象传递或引用传递,值会发生改变。
S1和S指向了同一个对象。

希望我的回答能帮助楼主解决问题。


作者: xieshuhua    时间: 2012-5-28 23:24
袁梦希 发表于 2012-5-28 23:14
这是关于值传递和对象传递的问题,
说白了就一句话:
当基本类型进行传递的时候是值传递,传递的大白话也就 ...

我想知道你这句话的来源 是那一本书。授人以鱼不如授人以渔~~
作者: 黄克帅    时间: 2012-5-29 01:03
设置i1的值不会导致i的值变化,你是通过局部变量 i 给 i1 赋值,改变 i1 的值会反过来改变 i 的值 那才奇怪。这个不用多说。
为什么设置s1会导致s的值发生变化?
因为你在new Input(s,i)(取个名字叫in);把 s 对象传给了 in对象中的 s1对象 ,这个时候in对象中的 s1 对象 的引用和 s 对象的引用都指向同一个对象,当调用set()方法的时候,你改变了s1 引用 指向的对象的值,s对象引用指向的值也就改变了。所以你打印出改变后的值
作者: xieshuhua    时间: 2012-5-29 07:08
黄克帅 发表于 2012-5-29 01:03
设置i1的值不会导致i的值变化,你是通过局部变量 i 给 i1 赋值,改变 i1 的值会反过来改变 i 的值 那才奇怪 ...

你说的很对,我很想知道解释这种现象的书籍,或者视频都行。貌似老师没有讲过这方面内容。求教。。。
作者: 贾旭    时间: 2012-5-29 09:54
  1. class Res{
  2.         String name="wang";
  3.         String sex="nv";
  4.         boolean flag = false ;
  5. }
  6. class Input{
  7.         private Res s1=new Res();
  8.         int i1;
  9.         int [] j1;
  10.          Input(Res s,int i,int [] j){
  11.           s1 = s;
  12.           i1=i;
  13.           j1=j;
  14.         }
  15.         public void set(){
  16.           s1.name = "lily";
  17.           s1.sex = "girl";
  18.           i1=3;
  19.           j1[0]=3;
  20.         }
  21. }
  22. class cw{
  23.         public static void main(String[] args) {
  24.                 Res s = new Res();
  25.                 int i=0;
  26.                 int []j={0};
  27.                 new Input(s,i,j).set();
  28.                 System.out.println(s.name+"."+s.sex+"."+i+"."+j[0]);//这里的s其实是和s1指向的同一个对象,这个楼上已经画图了.
  29.                                                                                                 //i为什么为0,因为i就是一个基本数据类型.不存在被多个变量指向
  30.                                                                                                //j[0]是引用数据类型,可以被多个变量所指向.
  31.        }
  32. }
复制代码
执行步骤:

Res s = new Res();//初始化s
int i=0;                 //定义一个局部变量i,又因为它是基本数据类型,不可以被多个变量指向.
int []j={0};          //定义一个int型的数组j.J是引用数据类型,它是可以被多变量指向的.
new Input(s,i,j).set();//重新给s1(也就是s)指向的变量初始化.
System.out.println(s.name+"."+s.sex+"."+i+"."+j[0]);//这里的s其实是和s1指向的同一个对象,这个楼上已经画图了.
                                                                                                //i为什么为0,因为i就是一个基本数据类型.不存在被多个变量指向
                                                                                               //j[0]是引用数据类型,可以被多个变量所指向.




如果你看了老毕视频,这些东西都有讲的哦.









作者: xieshuhua    时间: 2012-5-29 10:48
贾旭 发表于 2012-5-29 09:54
执行步骤:

Res s = new Res();//初始化s

再次增加字符串,来验证。
结果证明你说的引用数据类型完全不准确,如图所示。
另不要泛泛的说毕老师讲过,很难验证的,你如果听到过,麻烦说下第几天的第几节课讲的。
谢谢,希望共同提高~~
作者: xieshuhua    时间: 2012-6-3 20:55
本帖最后由 谢述华 于 2012-6-3 21:16 编辑

通过JVM知识解释下。
1、类s和s1
  1. 0: new #2; //class Res
  2. 3: dup
  3. 4: invokespecial #3; //Method Res."<init>":()V     //新建并初始化类s
  4. 7: astore_1
  5. 8: new #2; //class Res
  6. 11: dup
  7. 12: invokespecial #3; //Method Res."<init>":()V    //新建并初始化类s1
  8. 15: astore_2
  9. 16: aload_1
  10. 17: astore_2                                          //将s地址传递给s1,原来的s1被抛弃。
  11. 18: aload_2
  12. 19: ldc #4; //String lily
  13. 21: putfield #5; //Field Res.name:Ljava/lang/String;
  14. 24: aload_2
  15. 25: ldc #6; //String girl
  16. 27: putfield #7; //Field Res.sex:Ljava/lang/String;
  17. 30: return
复制代码
2、变量i和i1
  1.    0:   iconst_0    //传入的是常量0
  2.    1:   istore_1
  3.    2:   iload_1
  4.    3:   istore_2    //存储的是常量0
  5.    4:   iconst_3
  6.    5:   istore_2
  7.    6:   return
复制代码
3、字符串t和t1
  1. 0: ldc #2; //String xie
  2. 2: astore_1
  3. 3: aload_1
  4. 4: astore_2
  5. 5: ldc #3; //String buxie   
  6. 7: astore_2                  //常量池引用被改变
  7. 8: return
复制代码
4、数组j和j1
  1.   0:   iconst_1
  2.   1:   newarray int
  3.   3:   dup
  4.   4:   iconst_0
  5.   5:   iconst_0
  6.   6:   iastore
  7.   7:   astore_1
  8.   8:   iconst_3
  9.   9:   newarray int
  10.   11:  astore_2
  11.   12:  aload_1         //与类相同,引用改变,新建的数组被抛弃
  12.   13:  astore_2
  13.   14:  aload_2
  14.   15:  iconst_0
  15.   16:  iconst_3
  16.   17:  iastore
  17.   18:  return
复制代码





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