Java中的传值和传递引用

时间:2013-01-14 08:04:40

标签: java

  

可能重复:
  Is Java “pass-by-reference”?

我试图理解下面写的两个Java程序之间的区别:

 public class Swapping {

public static void main(String[] args) {

    IntWrap i = new IntWrap(10);
    IntWrap j = new IntWrap(20);

    swap(i, j);
    System.out.println("i " + i.i + ", j " + j.i);
}

public static void swap(IntWrap i , IntWrap j){

    int x = i.i;
    i.i = j.i;
    j.i = x;

    System.out.println("i " + i.i + ", j " + j.i);
}

}

public class IntWrap {

int i;
public IntWrap(int i){
    this.i = i;
}

}

输出:

i 20, j 10
i 20, j 10

第二个:

public class Swapping {

public static void main(String[] args) {

    Integer i = new Integer(10);
    Integer j = new Integer(20);

    swap(i, j);
    System.out.println("i " + i + ", j " + j);
}

public static void swap(Integer i , Integer j){

    Integer temp = new Integer(i);
    i = j;
    j = temp;

    System.out.println("i " + i + ", j " + j);
}

}

输出:

i 20, j 10
i 10, j 20

我无法理解即使我传递了Integer对象,它也应该在原始程序中交换。如果我在它上面写了包装类,那么它创建了什么区别,因为我只是再次传递对象。

4 个答案:

答案 0 :(得分:4)

所有方法参数(包括对象引用)都是通过Java中的值传递的。您可以为方法参数指定任何值 - 不会修改调用代码中的原始值。但是,您可以修改传递的对象本身,并且在方法返回时更改将保持不变。

J2SE API中有旧的Holder类,专门用于支持对具有“可返回参数”(例如IntHolderStringHolder)的方法的调用。它们主要与IDL语言生成的代码一起使用,因为IDL需要支持in,out和inout参数。这些持有人在其他代码中非常罕见。

您还可以使用数组模拟通过引用传递:

String [] a = new String[1];  String [] b = new String[1];

void swap(String [] a, String [] b) {
   String t = a[0]; a[0] = b[0]; b[0] = t;
}

答案 1 :(得分:1)

的UPS。 Integer对象在Java中是不可变的。您不能从其他方法更改其内部值,也不能。只创建新的Integer对象。

答案 2 :(得分:1)

Java使用call-by-value传递所有参数。当您将对象传递给函数时,对象引用(对象的地址)将通过value传递。在第二个程序交换中,您将分配i = j和J =温度。 所以我= 20的地址 j =地址10(新对象) 但是从交换返回之后,在主程序中我仍然指向10并且j指向20.这就是为什么你在主程序中得到10和20的原因。

但是在第一个程序中,您将对象的地址传递给swap函数,而在swap函数中,您正在修改这些地址所指向的对象的内容。这就是为什么它会在main方法中反映出来。

答案 3 :(得分:0)

(如果你不知道指针和参考文献,我建议你稍微讨论它们,那么这个世界会更有意义 - Intro to Pointers

归结为最简单的解释,java有两种方式来回传递所有内容:

  • Pass-by = Value:用于不可变对象( String,Integer,Double等)。如果重新创建对象,这些值不会更改,但有一个例外。

       String x = "World"; <- String x = new String("World");
       x = "Hello"; <- x = new String("Hello");
       x = x + " World"; <- x = new String("Hello" + " World");
       printOutString(x); <- printOutString("Hello World");
    

在一个记忆位置举行。任何更改都会创建一个与前一个无关的新对象,并查看单独的内存位置。

  • Pass-by-reference:用于非不可变对象( Classes,int,double等)。这些值可以更改,并且仍然保留在内存中的旧位置。

      int i = 1;
      i = 2; <- value at <reference-to-memory-as-value> = 2;
      i = i + 1; <- value at <reference-to-memory-as-value> + 1;
      printOutInteger(i); <- printOutInteger(value at <reference-to-memory-as-value>);
    

对此对象的任何更改都是对内存位置进行的。因此,位置永远不会更改(除非您创建新对象)。

您的计划也是如此。在方法中说出一件事的对象然后恢复为先前的值。在某种程度上,你是Operator Overloading。您为要发送的异议(在这种情况下为Integer)分配了新值,您已在方法中传递了值Integer i的值,因为{{1是不可变的,正在查看main方法中Integer的不同内存位置。因此,当方法退出时,您传递的对象将被丢弃,Integer iInteger i现在会查看其原始内存位置。

当您使用j个对象传递类时,因为它们 NOT 不可变,所以传递了内存位置(按值)并且处理了这些位置的值。这就是为什么这里的变化显示在原始对象中。

我希望这会有所帮助