您已经开发了以下代码。在交换方法中,我交换了两个对象的引用。然后它将在被调用的方法中更改(此处为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);
}
}
答案 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
仍然指向obj1
,B
仍然指向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)现在也可以用于垃圾收集。