通过值传递混淆并通过java中的引用传递

时间:2012-08-20 10:22:27

标签: java java-ee

  

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

您已经开发了以下代码。在交换方法中,我交换了两个对象的引用。然后它将在被调用的方法中更改(此处为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);

    }

}

3 个答案:

答案 0 :(得分:8)

传递给方法的对象作为引用传递,这意味着更改其成员将在外部看到,但引用本身是按值传递,这意味着不会看到更改引用由来电者。这是一个实验:

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
    }
}

答案 1 :(得分:7)

Java是按值传递的。

你只有两个对象。当您调用swap方法时,会复制两个新引用,但它们指向相同的对象。在该方法中,您只需更改复制的引用所指向的位置。但主要方法中的原始参考文献未受影响。

A - obj1
B - obj2

Acopy - obj1
Bcopy - obj2

方法之后:

Acopy - obj2
Bcopy - obj1

A仍然指向obj1B仍然指向obj2

答案 2 :(得分: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)现在也可以用于垃圾收集。