<翻译>Does Java pass by reference or pass by value?

E文地址:http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

 

Q:如果Java是传引用的,为什么swap方法不起作用?

A:你的问题说明了一个Java语言学习者共有的错误。确实,即使是有经验的老手也很难证明这是对的。

 

Java利用引用来操作对象,并且所有的对象属性都是引用。但是,Java关不利用引用来传递方法参数,而是利用值来传递。

 

请以下面的badSwap()方法为例子:

 

public void badSwap(int var1, int var2)
{
  int temp = var1;
  var1 = var2;
  var2 = temp;
}
 

当badSwap()返回时,通过参数传递的属性仍然保持他们原来的值。当我们把参数类型从int改为Object后这个方法仍然不起作用,因为Java也是通过值来传递对象引用。

这就是它变得复杂的原因:

 

public void tricky(Point arg1, Point arg2)
{
  arg1.x = 100;
  arg1.y = 100;
  Point temp = arg1;
  arg1 = arg2;
  arg2 = temp;
}
public static void main(String [] args)
{
  Point pnt1 = new Point(0,0);
  Point pnt2 = new Point(0,0);
  System.out.println("X: " + pnt1.x + " Y: " +pnt1.y); 
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
  System.out.println(" ");
  tricky(pnt1,pnt2);
  System.out.println("X: " + pnt1.x + " Y:" + pnt1.y); 
  System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);  
}

 如果我们执行这个main函数,我们会看到下面的输出:

 

X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0

 这个方法成功地修改了pnt1的值,即使它是通过值来传递的;但是,pnt1和pnt2的交换却失败了!这就是困惑的起源。在main方法里,pnt1和pnt2仅仅只是对象引用。当你传递pnt1和pnt2给tricky()方法,Java像其它参数一样利用值来传递引用,这意味着传给这个方法里的引用实际上是原始引用的拷贝。下面图一显示了Java传递一个对象给方法后,两个指向同一个对象的引用

 

图一.在被传递给一个方法后,一个对象至少会有两个引用

 

Java通过值来拷贝和传递引用,而非对象。因此,方法操作会修改对象,因为引用指向了原始的对象。但是因为在方法里的这个引用是拷贝的,交换操作会失败。如图二所示,方法引用虽然被交换了,但原始引用没有改变。不幸地,在一个方法调用结束后,留下给你的只有两个没有交换过的原始引用。如果想要成功地在方法调用外交换,我们需要交换原始引用,而非拷贝。

图二.只有方法引用被交换了,而不是原始引用

 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

Java中的“引用”是指非原生类型的变量的保存的是对一个堆上对象的引用。 
Java任何时候都是传的,只不过该的语义有所不同罢了

 

所有的参数传递都是 传值,从来没有 传引用 这个事实。 
所有的参数传递都会在 程序运行栈上 新分配一个 值 的复制品. 

 

注: 
传引用,  只有一种语法现象. 
就是 C++的一种语法 
void function(int & a){ 
   a = 1; 


这个实际上编译为 
void function(int * a){ 
   *a = 1; 


还是传的 地址值。

 

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

参数传递的问题。 
这里涉及到的基本功常识为: 
1. 每个Thread有自己的 运行栈。Stack 

2. 每次函数调用,运行栈顶部上都会为 该函数调用 分配一个Stack Frame.  这也称为Context. 

3. 函数调用结束,栈指针回到上一级函数调用的Context, Stack Frame, 刚才分配的顶部Stack Frame 就失效。上一级函数成为当前Stack Frame, Context。 

4. 每次函数调用, 参数都会 压栈 压入运行栈。注意,这是非常重要的。 

5. 压入运行栈内的 参数,是 Copy 了一份。注意,这也是非常重要的。所以,对参数 赋值,对上一级函数调用来说,是根本没有意义的。 
因为只是改变了顶部Stack Frame里面 参数Copy的内容,根本不对上一级 Stack Frame 造成任何影响。 

 

 

你可能感兴趣的:(java,thread)