0

可能的重复:
Java 是“按引用传递”吗?

我试图了解下面编写的 2 个 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

4 回答 4

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;
}
于 2013-01-14T08:21:51.717 回答
1

UPS。IntegerJava中的对象是不可变的。你不能从其他方法改变它们的内部值,也不能。只创建新Integer对象。

于 2013-01-14T08:06:11.270 回答
1

Java 使用按值调用来传递所有参数。当您将对象传递给函数时,对象引用(对象的地址)按值传递。在第二个程序交换中,您分配 i=j 和 j=temp . 所以 i=20 的地址 j=10 的地址(新对象)但是从交换返回后,在主程序中 i 仍然指向 10,j 指向 20。这就是为什么你在主程序中得到 10 和 20 .

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

于 2013-01-14T08:38:34.570 回答
0

(如果您不了解指针和引用,我建议您稍微复习一下,那么世界会更有意义 -指针简介

把它归结为最简单的解释,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方法中的值,因为Integer它是不可变的,正在查看Integer i与 main 方法中不同的内存位置。因此,当方法退出时,您传递的对象将被释放,Integer i现在j查看它们的原始内存位置。

当您使用int对象传递类时,因为它们不是不可变的,所以内存位置被传递(按值)并且这些位置的值被使用。这就是为什么此处的更改显示在原始对象中的原因。

我希望这有帮助

于 2013-01-14T09:38:18.687 回答