刚又看了个帖子,关于java参数传递的。我不认为我把这个问题彻底搞明白了,但我坚信真正搞明白这个问题的同学应该是屈指可数的。先看几个问题吧,希望明白的和不明白的同学都回复下,大家共同把这个问题搞明白。1int a = 1;
int b = a;
b = 2;
System.out.println("a=" + a);
System.out.println("b=" + b);如果有人觉得这个不像是参数传递那么我们写成下面的形式:public static void change(int b) {
b = 2;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
change(a);
System.out.println("a=" + a); }
2 和1差不多,我们换成String 来看看,String可不是基本类型哦。
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "abc";
String s2 = s1;
s2 += "d";
System.out.println("s1=" + s1);
System.out.println("s2=" + s2); }
如果认为这不叫参数传递可以像1那样修改下。
public static void change(String s2) {
s2 += "d";
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String s1 = "abc";
change(s1);
System.out.println("s1=" + s1); }3 最后看下引用类型或是说非基本类型再或者是对象类型,以int数组来举例。int[] a = new int[1];
a[0] = 1;
int[] b = a;
b[0] = 2;
System.out.println("a[0]=" + a[0]);
System.out.println("b[0]=" + b[0]);
同样可以做上面的修改:
public static void change(int[] b) {
b[0] = 2;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a = new int[1];
a[0] = 1;
change(a);
System.out.println("a[0]=" + a[0]); }
请大家就上面3段代码的结果给出理由。

解决方案 »

  1.   

    1、a=1。理由:b传值方式传入参数,不能改变方法外a的值。只是方法里的变量b被赋予了新值
    2、s1=abc。 理由:引用传递。对象“abc”由引用s1指向。传入方法change后,该对象有两个引用指向他。一个是s1,另一个是局部变量s2。s2 += "d";操作返回一个新的对象“abcd”,由局部变量s2指向他。而原来的“abc”对象的引用由原来的s1指向没有变。
    3、a[0]=2。理由:引用传递。 a指向数组A;0位被赋予1的值。该引用作为参数传入方法change里。
    局部变量b指向数组A;并对0位的值作修改,赋值为2。再用a取数组A的0位,值自然变成2了
      

  2.   

    1:int类型是传值,所以不会改变值。。
    2:String是个特殊的,只要给String新的值或者加值,JVM都会分配新的内存空间,
      String s1 = "abc";
      JVM给s1分配的内存空间假如是a,当你把s1传给方法也就是s2 += "d";
      时JVM会给s2重新分配空间,但s1还是指向a空间
      

  3.   

    第一段代码 全部都是基本数据类型,数据全部保存在栈中 b=a   实际上就是数据赋值
    第二段代码 String 是引用类型,但是他比较特殊,   b=a 实际上输出a的值就是b变量的值
    第三段代码 数组时引用类型  声明变量的时候 保存在栈中 但是一旦遇到new关键字 就会在堆内存中开辟一块空间并且把地址赋值给变量a  int[] a = new int[1];  
    如果b=a 的话 实际上就是把a空间(栈)里的地址给了b空间(栈)  a,b空间保存的地址引用的是同一个内存堆中的空间数据
    这个是我的理解
      

  4.   


    1.我想问你下,你认为1的两种写法实质一样么?
    2.为什么会返回一个新的对象"abcd".而3中却不返回一个新的数组对象呢?
      

  5.   

    1>  a=1 b=2
       理由:要理解一点,对基本数据类型的操作,都是操作的他的副本,也就是他的拷贝.首先a不用说.当执行int b = a 就是一个彻头彻尾的普通赋值方法.然后b =2 即将b的值进行改写.这个我觉得没什么可解释的.
    至于调用change(a);就不一样了.前面说过:对基本数据类型的操作,都是操作的他的副本.所以此处可以理解为传过去的是a的拷贝.更重要我觉得是一个作用域的问题.如果你把a作为全局变量,然后在change方法里对c进行修改试试.当然如果改成全局变量,又想在main函数里使用.肯定要改成static的,这又不一样了.而且我觉得你这样转换不是等价的...很牵强.
    2>首先字符串是不可变对象.是一个比较特殊的对象.首先s1指向字符串池中一块值为"abc"的区域,然后你对s2= s1 + "d";  因为不可变.所以他会重新产生一块内存区..所以打印出来s1="abc" s2="abcd"毫无疑问
    3>打印1和2.楼主我觉得你没想明白的主要原因是你不知道:首先对一个变量直接进行赋值和对他进行运算操作.是不同的概念..操作的永远都只是他的拷贝...但是如果是static的变量就不一样.而字符串列你可以把他理解为一个常量,一旦定义不可更改..
    而且我觉得你的改写和你没必写之前要表达的意思不一样..如果非说一样,我觉得很牵强
      

  6.   

    KO..回个贴就没有板凳了..还好先抢了SF
      

  7.   

    什么叫传值???????我也知道String的不可变性,请问他的不可变性在JVM中是如何处理的,能从堆栈的方向去分析么?
      

  8.   

    帖一段代码run一下;感觉一下
    [/
    public static void change(String a) {
    a = "aa";
    }

    public static void changeBuffer(StringBuffer a) {
    a.append("a");
    }

    public static void main(String[] args) {
    String b = "b";
    change(b);
    StringBuffer c = new StringBuffer("c");
    changeBuffer(c);
    System.out.print(b);
    System.out.print(c);
    }
      

  9.   

    1 你确定对基本类型的操作是操作他的副本???
    你的意思是 b=a 的时候会在内存中再放入一个1,JVM真的是这样做的吗?你从什么来确定的。
    2 你说到了字符串池,那你对常量池有了解吗,这两个有什么关系知道吗?
      

  10.   

    为什么没人看这段呢。
    方法里的变量都是局部变量;作用区域在方法内。但该局部引用变量所指向的对象如果是可修改的;那就可以修改;方法指向该对向的引用得到的是修改后的结果。String是不可修改的。所以s1指向那个对象就是那个对象
      

  11.   

    我确定,如果你非要我拿什么来证明,那我只告诉你去问JAVA创始人,看他当初设计的时候是不是这样的..
      

  12.   


    amos1989 再问你下吧,有没有想过:
    int a = 1;
    int b=1;
    a=b 是ture 的实质是什么呢?
    他和 
    String s1 = "abc";
    String s2 = "abc";
    s1=s2 
    是否有什么联系、
      

  13.   

    1、值传,理由,8大基本类型之一,JAVA的基本类型都是这样规定,这个没什么好说
    3、引用副本,理由,也是JAVA规定,非基本类型的都是这样,也是没什么好说2、类似1,理由,String是特殊类,String底层是由char[]构成,JAVA的JVM也有个字符串池,其实说明白点String还是类,不过它是由char[]数组组成,不过这些实例不由我们操作,由JVM的自己处理,所以当我们使用String s = "";的时候,JVM在后面已经帮我作了一些判断,到底是new呢还是返回已有值
    总的来说2,可以看成基本类型使用,但要心底记着,它其实还是个类,只不过JVM做了我们不知道的处理以上是我愚昧的理解
      

  14.   

    传入的引用和基本类型都是副本。
    只是引用可以指向一段地址;如果这段地址可修改;并且在方法里被修改过了。那么方法外指向这段地址的引用就得到了修改后的结果。String的特殊在于它不可修改。
      

  15.   

    希望你能从 
    int a = 1;
    int b=1;
    a=b 
    得到启发。很高兴能和你讨论,但是你的回答让我不满意哦,呵呵。
      

  16.   

    能否说一下你说的 值传 的含义是什么。是将基本类型的值复制一份出来么?那么你和amos1989 的理解是一致的。
      

  17.   

    ER。。因为回帖太多人,文字又多,偶没看amos1989的回帖基本类型不是类,所以int i = 10;的时候,i引用的值也就是10,我这里说的值传,就是把这个10再复制出来一份int i = 10;
    int j = i;//这里就把i引用指向10的这个值,复制(副本)到j引用上去所以当你操作i的时候,和j是没关系的
      

  18.   

    我敢肯定是..我们公司有一个牛人.对于这些研究很深..不过他现在很忙.是他告诉我的..曾经我也是问了一个这样类似的问题. 他是OGSI标准的委员
      

  19.   

    1.我干才说的赋值意思就是同于C语言中的变量赋值
    2.String 类型和基本类型不同
    在我的印象中String类型赋值的话他会放弃自己引用的空间而从新开辟一块新的空间来被赋值
    如果String s="abc";
              s+="def";
           在我的印象中是abc这个空间就别仍掉了,会从新开一个空间,给这个s赋值 而这个s是个新的引用空间  这个是我的理解 可能不正确
      

  20.   

    认为是复制值。反证法:
    假设是复制地址。
    那么1中
    public static void change(int b) {
    b = 2;
    }
    b就指向了这个地址。并且修改了这个地址的值。
    与结果不符。那么剩下就是复制值了。
    b改变的是复制的值,与本身没有影响。
      

  21.   

    new String的问题,参数传递问题,web/dbms的乱码问题,未来还会反复出现的。感谢兔子大哥的总结。
      

  22.   

    我觉得,基本类型的参数传递,是对值进行了复制。保持这一点,很多问题都很容易就想通了.就发现不再是问题.
      我想起了一个问题..
      请看如果一段代码,如果不在eclipse里运行,请写出输出结果                  public static void main(String[] args) {
                                int j = 0;
                                for(int i = 0; i < 100 ; i ++){
                                   j = j ++;
                                }
                                System.out.println(j);                   }
    你看下答案是什么?
      

  23.   

    这问题。除非JAVA没人用了
    或者人类灭绝了
    不然过段时间又会冒出来D。。
      

  24.   

    我所了解的,基本类型是入栈的,跟String差不多,具有不可变性,能否帮我问他下相关的东西,因为这个我也不敢确定,看到一些书上这样讲。
      

  25.   

    在Java中只有传值这一说法,只是基本类型的数据与复合类型的数据存储位置不一样而已。
      

  26.   

    嗯 说到了重点了,这也是很多人想不明白的地方,我先说下我的观点,我不认为是复制了值,据我了解,jvm对基本类型的处理比较特殊,是存放在栈中,也有说法是常量池。
    b=2时,因为b之前指向了1,当改变 =2 是 ,jvm首先会到栈中查找是否有2,如果有,就将b指向2,如果没有就在栈中放2 然后 b指向2,而原来的 引用a 和 栈中的1 都没有变化。我有一点可以证明这个观点,就是我上面说的:
    int a = 1;
    int b = 1;
    a=b
      

  27.   

    没空看,太长了。基本类型传值。函数里面怎么变都不会影响外面的值。
    复杂类型传引用。如果你修改对象内的值(例如调用set方法),外部是受影响的。如果用=直接操作对象,还是引用传递,外部不受影响。别拿String说事,因为不可变,可以当它是基本类型看待了。
      

  28.   

    这个问题涉及到了++j 和 j++的问题。不足以说明什么,你可以运行下面代码
    public static void main(String[] args) {
    int j = 0;
    for (int i = 0; i < 100; i++) {
    j = ++j;
    }
    System.out.println(j); }
      

  29.   

    对于44楼的认为我不赞同..
     还是这个程序.
    public static void main(String[] args) {
    int j = 0;
    for(int i = 0; i < 100 ; i ++){
    j = j ++;
    }
    System.out.println(j);}如果按照你的分析,那么输出的是100,但实际上输出的肯定是0.
    同样,在你对基本数据类型进行操作后,他会生成在内存中划分出另外一块内存区.首先刚开始J = 0 , 在J = J++的时候, 等号前面的那个J已经不是J声名时的那块内存区了,JVM为他重
    新为他分配一块新的内存区.也就是入栈..比如说,int j = 0 时,j的内存地址为00xx01,值为0。那么经过第一循环的以后前面那个J内存地址为00xx02,值为0,而后面那个J(内存地址00xx01)则会进行++操作,此时他的值为1,不过他已经不能影响到前面J的值了,此时J的内存地址就已经是等号前面的那个J的内存地址了(00xx02),再进行第二循环的时候,j的内存地址是:00xx02,值是0,至于00xx01那块内存区域,因为已经没有人再使用,所以将会在下一次垃圾回收的时候被GC回收,此时他(内存地址为00xx02的J)变成后面的那个j,前面那个J 则又会重新分得一块新的内存区域00xx03,值仍然是0,而00xx02则又会被丢弃然后被GC回收,依此类推,直至最后打印时J仍然为0,但他的内存地址已经不是最开初的00xx01了,换句话说,他已经不是当初的那个J了。
      

  30.   


    或者你改成
    public static void main(String[] args) {
    int j = 0;
    for (int i = 0; i < 100; i++) {
    j += 1;
    }
    System.out.println(j); }
    再看看。
      

  31.   

    这个我觉得应该分开来来说先是使用,在使用的角度来说,不管你底层是复制也好,寻找相同也好,在使用的角度来说,就是复制一个值,从而使得2个不同的引用指向不同的值然后是实现,你说JVM是怎么实现使用上的功能,这个又要另外讨论了,再而且每个平台的JVM实现都不一样,或者是到栈找值,或者直接新建一个,这个就要看JVM吧
      

  32.   

    你说得很对,两种解释 其实都能很好的解释值传递的问题。我也想尽量接近问题的本质而已。
    或许你可以帮我解释下:
    int a = 1;
    int b= 1;
    a=b
    的问题。非常感谢。
      

  33.   

    我觉得就是复制一个值..但是JVM是怎么样实现的,我想这个以我们目前的技术水平讨论三天三夜也是个无果...
      

  34.   


    而后面那个J(内存地址00xx01)则会进行++操作,此时他的值为1,
    其实这个时候后面那个J还不是1哦。记住j++是先赋值再做运算。所以你这里不管怎么循环j都是0.你认同我的观点吗?
      

  35.   

    JAVA中有规定,基本数据类型 == 比较的是两个变量的值.而不是地址..
    所以我们可以把他们理解为:现在有2个盒子a,b.里面都装着一个1. 当他们进行a==b的比较操作时,实际上去取出他们盒子里面的东西出来进行比较
      

  36.   


    先把后面那个J的值拷一份给前面那个J.然后对后面内在地址中的J+1
      

  37.   

    这种问题结束不了。
    建议自己画个内存示意图,其实很容易懂。
    有兴趣的可以去翻一下《Core Java》,有图有真相。
      

  38.   

    妈的.一个用户不允许连续三次回贴..擦..而且还有一点...
      j =j++
    那么我问你,j++肯定是执行了对不对? 只不过是在赋值以后执行的.
        如果变量进行基本操作的时候,不是对变量进行复制..
      那么前面的那个j和后面那个j就是同一个内存地址.那么即使是先把后面的j的值赋给前面的j,再对后面的j进行++操作,那么由于他们是一个内存地址,其实前面j的值还是发生了改变对不对??? 那么第二次循环的时候他就不再为0了.可是你打印一下,每次循环他都是0.说明他们不是同一个内存地址对不对??既然是同一个变量,却又不是同一个内存地址?怎么解释?除了复制这种解释外..
        为什么不尝试着用我的这种思维方式想一下列?? 一定要先入为主?
      

  39.   

    那就再总结下吧。
    int a = 1;
    int b = a;
    b=2;
    其实说来说去,问题的关键是在这里:
    你们的看法:
    在int b = a;的时候,就已经对1进行了复制。
    然后在 b=2;时改变b指向的1=2;
    而我的看法:
    int b = a;的时候并没有对1进行复制。
    而是在 b=2的时候,向栈中直接添加2,再让b指向2.
     

    大家可以对比两种做法对内存的耗费情况和操作的复杂度,我相信JVM的设计者是明智的!
      

  40.   

    JAVA中有规定,基本数据类型 == 比较的是两个变量的值.而不是地址..无意冒犯,但是如果你连这个都没搞清楚那我白跟你讨论了。
      

  41.   

    我是这么理解的:
    第1题第2段,在 
                    b = 2;
    的下边在加一个输出
    System.out.println("a=" + b);
    再看结果就很明显了,b = 2 这句里的变量b是在change方法里产生的,那作用范围也就只是在change里。
      

  42.   

    b是方法chang的形参,当然是在chang之内啦。呵呵
      

  43.   


    大兔子大概能再下个结论了吧
    你说a==b这问题嘛,还是要分角度说下去
    我们说专业点,用OO的角度来说,是相等的,不过只限于基本类型
    要是按C、汇编…………等等角度来说,问是根据地址相等还是值相等,不同JVM有不同的做法,可能某天SUN(还是应该说是Oracle呢)觉得这样效果不好,用一种新方式作判断那么到时候又是一大片的讨论所以这个既然JAVA说是OO编程,我们就看着OO来做事
    至于底层怎么实现,用OO来说,觉得也不太现实,底层的问题还是C++、C、汇编吧(虽然这2门我都没学过)
      

  44.   

    你爱怎么想怎么想..关我叼事..浪费时间....
        你我都不是JVM的设计者,不过是找一个合适的解释方式,让自己的想法说得过去..
    JAVA中有规定,基本数据类型 == 比较的是两个变量的值.而不是地址..无意冒犯,但是如果你连这个都没搞清楚那我白跟你讨论了。
       -------> 你看清楚.我是怎么说的....自己要钻牛角尖..你就继续钻...
        
      

  45.   

    引用传递,完全可以直接理解为复制...  这是最后一次回贴...你爱怎么想就怎么想..不关我事..我觉得找一个自己能说得通的理由,让自己明白就行..
         
           看楼上那些人还鸟你....没意义的..如果JVM是你设计的..你说什么我都相信...
     
    无意冒犯...就看不惯人老钻牛角尖..
      

  46.   

    又是这个问题JAVA里只能改变参数的属性值,不能改变参数的值
    所以change(int i){
      i = 100;
    }
    对 i 是没什么影响的
    而 change(Object o){
      o.attribute
    }
    则改变了 o 的属性值 但 o 本身的值(即地址) 是不会有任何改变的
    说到底 Java 还是有指针的  引用就是
    Java也不是纯粹的面向对象,几个基本数据类型就很尴尬
    所有后来jdk5.0 就有封箱解箱了
    说说就要到内存的分配了,就此打住
      

  47.   

    还是保留基本类型这说法好点第一,现在的教育都大量灌输了这概念,硬把抹杀掉了还是一片混乱
    第二,好让JAVA语言搞点“特色”
    第三,要是把基本类型抹了要是别人问你,C++和JAVA你说一个面向过程,一个面向对象,有啥区别啊,大家还不是一样写一堆类一堆变量一堆…………
    第四,个人来说已经习惯JAVA这么个思维了,就放过我吧
      

  48.   

    不是恼羞成怒.首先你是JVM设计者吗?或者这里有JVM设计者吗?? 有人研究过JVM怎么设计的吗??
     如果没有,那我们能确切的知道JVM对于这个问题是怎么设计的???
      如果不能.那么只不过是给自己找一个适合的解释,去说通这个问题...
        如果非要这样争下去...跟讨论先有鸡还是先有蛋有区别吗???有些问题,适可而止.
            如果你说为了研究学术...我无语可说,但我要说的是有必要吗???
               如果要搞清楚SSH的具体实现?我们不是原理性理解,应用熟练就行???莫不成你还要去写一个SSH出来?? 语言说到底就是一个工具,用JAVA也好,C也好.我们只不过是做开发.不是做研究.何况对于不同的系统
    JVM也有不同的实现..
           就像平时我们写算法,对于同一问题,可能就多种算法. 你个人肯定会偏向于一种.如果这个算法题让你制定标准.那么你肯定采用你偏向的算法..但那一天这个标准不要你来维护了.换人了.别人觉得不好,于是又可以把算法替换他偏向的..
           同样的道理...多的我也不说了...对于这个问题的理解,我只能理解成这样.我觉得我自己能把自己糊弄过去就行了.....
      

  49.   

    http://topic.csdn.net/u/20100401/14/9e88a4ca-3eb3-4c92-bdd4-5de3613bc7b5.html
      

  50.   

     
    amos1989 请看:
    http://blog.csdn.net/ZangXT/archive/2009/08/05/4410246.aspx