1

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

嗨,我开发了以下代码。在交换方法中,我交换了两个对象的引用。然后它将在被调用的方法中更改(这里是 swap()),但在主方法中没有更改..为什么?

class Check
{

    public void swap(PassByRefDemoMain obj1,PassByRefDemoMain obj2)
    {

        PassByRefDemoMain temp;
        temp=obj1;
        obj1=obj2;
        obj2=temp;
        System.out.println(obj1.id+ " "+ obj2.id);

    }
}


public class PassByRefDemoMain {
    int id;
    PassByRefDemoMain(int id)
    {
        this.id=id;
    }
public static void main(String[] args) {
        PassByRefDemoMain obj1=new PassByRefDemoMain(10);
        PassByRefDemoMain obj2=new PassByRefDemoMain(20);

        Check obj=new Check(); 
        obj.swap(obj1,obj2);

        System.out.println(obj1.id + " " + obj2.id);

    }

}
4

3 回答 3

9

您传递给该方法的对象作为引用传递,这意味着更改其成员将在外部看到,但引用本身是通过 value 传递的,这意味着调用者不会看到更改引用。这是一个实验:

class Person {
    public String name;
}

class Test {
    public static void changePerson(Person p) {
         p.name = "Tudor";
         p = null;
    }

    public static void main(String[] args) {
        Person p = new Person();
        p.name = "John";
        changePerson(p);
        System.out.println(p.name); // prints Tudor and you don't get NPE
    }
}
于 2012-08-20T10:24:56.960 回答
7

Java 是按值传递的。

你只有两个对象。当您调用该swap方法时,会复制两个新引用,但它们指向相同的对象。在该方法中,您只需更改复制的引用指向的位置。但是 main 方法中的原始引用保持不变。

A - obj1
B - obj2

Acopy - obj1
Bcopy - obj2

后方法:

Acopy - obj2
Bcopy - obj1

但是A还是指向obj1B还是指向obj2

于 2012-08-20T10:25:17.440 回答
0

正如人们敏锐地指出的那样,java总是按值传递。

碰巧一个对象的“值”是它存储在堆上的内存地址。所以这就是发生的事情:

Object o = new Object();

右手边在堆上分配空间,我们会说在位置 1000 左手边在堆栈上分配一个变量,我们会说在位置 100,并且由于分配包含对象的“值”,这是1000,它在堆上的位置。你的记忆现在看起来像这样:

Stack
---------------------------
====== caller stack frame ==== 
100(o)    ==>     1000
==============================

Heap
------------------------------
1000   ==>   object data 1

现在您进行方法调用:

void foo(Object x) { .... }
foo(o);

为方法调用创建了一个新的堆栈帧(显然是在堆栈上)。在堆栈上创建一个新变量,例如在位置 200,并给定传递对象的“值”,即 1000,它位于堆上。

所以在方法实际运行它的代码之前,你的记忆看起来像这样

Stack
---------------------------
====== caller stack frame ====
100(o)    ==>     1000
==============================
====== foo stack frame =======
200(x)   ==>     1000
==============================

Heap
------------------------------
1000   ==>   object data 1

因此,如果您现在在您的方法中执行此操作:

void foo(Object x) {
   x = new Object();
}

您将在堆上分配一个新对象,假设在位置 2000,并将方法参数变量分配给它的位置,因此您的内存现在看起来像这样:

Stack
---------------------------
====== caller stack frame ====
100(o)    ==>     1000
==============================
====== foo stack frame =======
200(x)    ==>     2000    
==============================

Heap
------------------------------
1000   ==>   object data 1 
2000   ==>   object data 2

当方法退出时,堆栈帧被丢弃,你又回到了这个:

Stack
---------------------------
====== caller stack frame ====
100(o)    ==>     1000
==============================

Heap
------------------------------
1000   ==>   object data 1
2000   ==>   object data 2

请注意,“o”仍然指向相同的对象数据。第二个分配的对象(位置 2000)现在也可以进行垃圾回收。

于 2012-08-20T13:10:25.547 回答