public class Test{
public Test(){
StringBuffer a=new StringBuffer("a");
StringBuffer b=new StringBuffer("b");
m(a,b);
System.out.println (a+"  "+b);
}
public void m(StringBuffer x,StringBuffer y){
x.append(y);
y=x;
}
public static void main(String args[]){
Test t=new Test();
}
}为什么输出的结果是ab b ,而不是ab ab 呢?这题里的m()中是不是传递的是对象?如果传的是对象是不是就是按引用传递?这样会改变原来数据的值?

解决方案 »

  1.   

    首先这里m(a,b);调用方法m的时候把a,b两个对象按引用传递到方法里的参数变量x,y;也就是x现在引用对象a的引用,y引用对象b的引用
      然后在方法m里,先x.append(y);对x也就是对象a的引用进行操作,所以直接改变了对象a的值为:ab
      再用y=x;这句,把x引用的对象a的引用赋值给y变量,也就是此时y变量重新引用向了a对象,而对b对象没有任何影响.
      

  2.   

    也就是说,在进入m()时,y和b指向了同一内存
    y = x只是让y指向x指向的内存
    而并没有让a改变指向,是吧??学习!!
      

  3.   

    x,y分别是a,b的两个引用的拷贝.a通过x改变了原来的值,而y=x是将原本指向b的引用指向了a.
    最后x,y,a指向的是同一个对象
      

  4.   

    这个问题总有人问的,问题关键就出在java参数传递只传值不传引用,但是java对象又只代表引用,总之总结下来就一句话,如果参数是普通类型,不用考虑,函数内部对他们无法影响,如果参数是对象,函数内部凡是通过调用此对象自身函数而改变其值的,将会影响到参数原型,否则和普通类型一样,毫无影响。
      

  5.   

    如果非要深究原理,我觉得是这样的:java参数传值就是所谓的深度拷贝,而当参数本身是对象时就会遇到一个问题,因为java中对象都是引用,所以即便被深度拷贝,它也是引用的拷贝。如果对这个引用的拷贝用=更改的话,只是讲引用的拷贝指到了另外的内存地址,源引用显然不受影响。但是如果调用引用拷贝中的成员函数就不一样了,引用的拷贝,甚至是引用的拷贝的拷贝的拷贝的拷贝的拷贝的拷贝的拷贝的拷贝最初指的内存地址也是一样的,这样显然和=的效果不同,自然会影响到源对象了。
      

  6.   

    x,y分别是a,b的两个引用的拷贝
    在整个过程中x一直指向a的内存地址,也就是说x是a的一个引用,语句x.append(y);把x的值改为
    "ab",由于x是a的一个引用,StringBuffer对象a的值也变为"ab",语句y=x;是使x的内存地址赋给
    y,此时y指向了x所指向的内存地址,也就是a的地址,此时的y就和对象b无关了,虽然执行该语句后
    y的值变为了"ab",但是由于它和b并无关联,所以对b的值不造成影响,结果就是"ab  b"了
      

  7.   

    有兴趣的话可以看看以下的程序,有助于理解String 和 StringBuffer 的区别;也就是理解什么是immutable object。public class Test{
    public Test(){
    String a=new String("a");
    String b=new String("b");
    m(a,b);
    System.out.println (a+"  "+b);
    }
    public void m(String x,String y){
    x = x + y;
    y = x;
    }
    public static void main(String args[]){
    Test t=new Test();
    }
    }
      

  8.   

    楼上的代码中,为什么String a,b的最终值没有变呢?难道这里的String a,b不是一个对象吗?
      

  9.   

    我看lip009(深蓝忧郁) 的解释就就很好了。
    这主要还是关于引用方面的东西。
    而对于dragon311() 的问题,就是关于String和StringBuffer对象的区别了。
    因为“String类是用来表示字符串常量的,用它创建的每个对象都是字符串常量,一经建立便不能修改.”如果是改变的话也应该是重新创建了新的对象后的改变,所以说在使用String时要把他当作一个常量,而使用StringBuffer时,把他当作变量来使用。
      

  10.   

    m()是按照引用传递的.调用m(a,b)时,把a,b对象的引用传递给了x,y.然后调用了x.appent(y), 给x在最后又加了一个字符串,也就是x变成了ab,即变量a的输出结果为ab.之后又调用了y=x.是把x的引用传给了y,这时y已经不再指向原来对象b所指向的对象了,但是b的引用值自始至终没有改变,所在在输出时结果为b,
    也就是最终输出结果为:ab,b
      

  11.   

    nighthawk(我们孤单,我们并肩) ( ) 信誉:76    Blog  2006-8-29 0:11:11  得分: 0  认为说得对,java所谓的参数引用,实际是引用的copy。
      

  12.   

    x=y
    只是传了引用
    b还是原来的b,并没有赋值
      

  13.   

    这是JAVA里函数的参数是是引用拷贝的问题,
    你在外面定义乐变量,传进函数里的只是一个拷贝,它和外面的变量指向同一个对象,所以你可以调用函数,但改变拷贝,并不会对外面的变量有影响
      

  14.   

    Fitzwilliam(微尘) 你举的例子不好 我想你改成StrignBuffer是一样效果的
      

  15.   

    我画个图,大家看看我的理解对不
    这是刚进如m(x,y)方法时
     这是最开始:
      a    x           b   y
      ↓   ↓          ↓  ↓
     __________      __________
    |  "a"     |    |   "b"    |
    |__________|    |__________|
    这是执行了x.append(y)之后
      a    x           b   y
      ↓   ↓          ↓  ↓
     __________      __________
    |  "ab"    |    |   "b"    |
    |__________|    |__________|
    这是执行了y=x 一句之后:
      a   x  y           b   
      ↓  ↓ ↓          ↓  
     __________      __________
    |  "ab"    |    |   "b"    |
    |__________|    |__________|
    m(x,y)方法执行完了之后:
      a                  b   
      ↓                 ↓  
     __________      __________
    |  "ab"    |    |   "b"    |
    |__________|    |__________|此时执行System.out.println (a+"  "+b);结果自然是 ab b
      

  16.   

    刚才发的没对,大家看不清楚,重新发一次(不懂怎么编辑自己的回复,借地问一下)
    这是刚进如m(x,y)方法时
       a    x           b   y
      ↓   ↓          ↓  ↓
     __________      __________
    |  "a"     |    |  "b"     |
    |__________|    |__________|
    这是执行了x.append(y)之后
       a    x           b   y
      ↓   ↓          ↓  ↓
     __________      __________
    |  "ab"    |    |   "b"    |
    |__________|    |__________|
    这是执行了y=x 一句之后:
      a   x  y           b   
      ↓  ↓ ↓         ↓  
     __________      __________
    |  "ab"    |    |  "b"     |
    |__________|    |__________|
    m(x,y)方法执行完了之后:
     a   x  y           b   
      ↓  ↓ ↓         ↓  
     __________      __________
    |  "ab"    |    |  "b"     |
    |__________|    |__________|此时执行System.out.println (a+"  "+b);结果自然是 ab b
      

  17.   

    只要记住,java只有传值就可以解释所有类似的现象了。
      

  18.   

    在这个程序中,使用String和StringBuffer得到的结果是不同的。
    这是因为每一个String对象都是immutable对象;而StringBuffer是mutable的。通过下面的例子可以证明这一点:
    public class Test{public static void main(String args[]){ String s1="1";
    String s2="2";
    String s0=s1;

    System.out.println(s0==s1); //s0,s1指向同一个对象
    s1=s1+s2;
    System.out.println(s0==s1);//s1已经指向了另一个对象 StringBuffer sb1=new StringBuffer("1");
    StringBuffer sb2=new StringBuffer("2");
    StringBuffer sb0=sb1; System.out.println(sb0==sb1); //sb0,sb1指向同一个对象
    sb1.append(sb2);
    System.out.println(sb0==sb1); //sb0,sb1仍然指向同一个对象//取消下面语句的注释可以看到s0的值没有改变,而sb0的改变了
    // System.out.println("***********\n"+"s0 = "+s0 +"\nsb0 = "+sb0);
    }
    }简单解释一下:
    在对一个immutable对象进行操作的时候,如果你改变了它的值,实际上你并没有改变原来的那个对象,而是得到了一个新的对象;上述例子中s0,s1指向的变化证明了这一点。
    而对一个mutable对象进行操作的时候,才是真正改变了操作对象。如sb0,sb1所示。
      

  19.   

    JAVA与C和C++不同,只有值传递,没有地址传递,从根本上来说,JAVA取消了C中的指针,因为指针使用复杂并且容易出现错误。
        JAVA是全完全面对象的话语言,在定义对象时,在内存中产生了该类的一个引用。在参数传递过程中所传的就是这个引用值。因此b的引用传给了y,所以b和y引用共一个对象,当y的对象改变时b的对象也改变,所以输出为BA。然而y = x;只是将引用值改变,对象没有改变,所以输出结果没有变化。
      

  20.   

    比较底层的问题了,其实一句话就可以说清楚:java中函数是传引用的复制public void m(StringBuffer x,StringBuffer y){
    x.append(y);
    y=x;
    }y=x;这句,是将传进来的引用y指向了x,而原来的函数外的实参b的引用没有变,y此时与b已无任何关系了(俗称'野指针')
      

  21.   

    zliloveu(小刁) 的图很好,就是这样的。
      

  22.   

    MS  <<Java Puzzles>>上面的东东··~~
      

  23.   

    1没有引用指向的内存区域才会被garbage
    2引用是地址值但是不透明,java是传值的引用也是值