改变Java中传递的参数(通过ref,value调用)

1 java parameter-passing

我实际上认为我很清楚Java中的值传递是如何工作的,因为那是我通过的SCJP证书的一部分.直到今天,当我在工作时发现了这样的方法:

public void toCommand(Stringbuffer buf) {

  buf.append("blablabla");
}
Run Code Online (Sandbox Code Playgroud)

然后该方法的调用者使用如下函数:

StringBuffer buf = new StringBuffer();
toCommand(buf);
String str = buf.toString();
Run Code Online (Sandbox Code Playgroud)

现在我认为该代码会给str值"",但实际上它给了它来自mehod的值.这怎么可能?我觉得Java中没有像那样的东西?

无论哪种方式......在Java中编写这样的代码应该被视为一种不好的做法,对吧?因为我可以想象它会带来一些混乱.

我实际上花了一些时间来搜索这个,但我对这些消息来源的解释是,它不应该工作.我错过了什么?

http://www.yoda.arachsys.com/java/passing.html
http://javadude.com/articles/passbyvalue.htm
Run Code Online (Sandbox Code Playgroud)

塞巴斯蒂安

T.J*_*der 11

Java是按值传递的.对象引用的是对象引用,而不是对象本身.因此,该toCommand方法接收值的副本,该副本是对象的引用 - 与调用者引用的对象相同.

这与从两个变量引用对象时完全相同:

StringBuffer buf1;
StringBuffer buf2;

buf1 = new StringBuffer();
buf2 = buf1; // Still ONE object; there are two references to it
buf1.append("Hi there");   
System.out.println(buf2.toString()); // "Hi there"
Run Code Online (Sandbox Code Playgroud)

无偿的ASCII艺术:

                  +--------------------+
    buf1--------->|                    |
                  | === The Object === |
                  |                    |
    buf2--------->|    Data:           |
                  |      * foo = "bar" |
                  |      * x = 27      |   
                  |                    |
                  +--------------------+

另一种思考方式是JVM具有所有对象的主列表,由ID索引.我们创建一个object(buf1 = new StringBuffer();),JVM为对象分配ID 42并buf1为我们存储该ID .每当我们使用时buf1,JVM从中获取值42并在其主列表中查找对象,并使用该对象.当我们这样做时buf2 = buf1;,变量buf2获得值42 的副本,因此当我们使用时buf2,JVM会看到对象引用#42并使用相同的对象.这不是一个字面上的解释(虽然从平流层的角度来看,如果你把"JVM"看作"JVM和内存管理器和操作系统",它不是一百万英里的距离),但有助于思考实际上是什么对象引用.

在该背景下,您可以看到如何toCommand获取引用(42或其他),而不是实际的StringBuffer对象数据.因此,对它的操作在主列表中查找并改变其状态(因为它保存状态信息并允许我们更改它).调用者看到对象状态的更改,因为对象保持状态,引用只指向对象.

无论哪种方式......在Java中编写这样的代码应该被视为一种不好的做法,对吧?

一点也不,这是正常的做法.如果不这样做,就很难使用Java(或大多数其他OOP语言).相比于类似的图元对象是大intlong,所以他们是走动昂贵; 对象引用是基元的大小,因此它们很容易传递.此外,拥有事物的副本使得系统的各个部分难以进行交互.引用共享对象使其变得非常简单.