我读了this excellent article并且它有意义:Java严格按值传递;当一个对象是一个参数时,对象的引用按值传递。
但是,我完全混淆了为什么以下代码段可能会起作用。
Foo
有一个String成员变量a
,它是不可变的,每次都需要刻录。
第一种刻录方法(注释掉)应该可以正常工作。
第二个方法设置a
对传递的值的引用。如果newstr
是临时变量,它应该不起作用。预期的输出结果是:
Totally temp
NULL
然而,我得到了
Totally temp
Totally temp
为什么呢?临时变量引用仍然很好,这只是纯粹的运气吗?
public class Foo {
String a;
public Foo(){}
public void burna(String newstr){
// a = new String(newstr);
a = newstr; /*this should not work: */
}
}
public class foobar {
Foo m_foo;
public foobar(){};
public void dofoo(){
String temp = new String("Totally temp\n");
m_foo.burna(temp);
System.out.print(m_foo.a);
}
}
public static void main(String[] args) {
Foo myfoo = new Foo();
foobar myfoobar = new foobar();
myfoobar.m_foo = myfoo;
myfoobar.dofoo();
System.out.print(myfoo.a);
}
答案 0 :(得分:11)
Foo有一个String成员变量a,它是不可变的,每次都需要刻录。
不,它没有:它没有标记为final
:
public class Foo {
String a;
...
}
变量是完全可变的 - 您可以随时更改它以引用不同的字符串,这就是您在burna
方法中所做的。
我目前不知道为什么你认为这不起作用:
public void burna(String newstr){
a = newstr; /*this should not work: */
}
将a
的值设置为newstr
的值 - 这是对字符串的引用(或null)。这就是它所做的一切。我不确定你在变量中“燃烧”是什么意思。
您正在调用burna
并传入对文本为“Totally temp \ n”的字符串的引用 - 因此a
设置为对该字符串的引用。
你是什么意思“如果newstr
是一个临时变量,它应该不起作用。”没有“临时变量”这样的东西。有一个本地变量 - 但是一个对象不会因为引用它的变量超出范围而被销毁。那会让你感到困惑吗?
你的程序有几件事情发生了 - foobar
类在理解方面可能没有帮助你。您是否可以尝试将代码简化到令您感到困惑的程度,但是进展较少?然后我们可以更准确地隔离混淆的来源。
答案 1 :(得分:3)
问题似乎是您不了解垃圾收集的工作原理。只要对象的至少一个引用保持有效,就不会收集该对象。
答案 2 :(得分:2)
字符串“Totally temp \ n”有两个引用。一个是temp
,另一个是a
对象中的Foo
。在dofoo
temp
结尾处超出范围,因此减少了一个参考。但是你还有另一个引用,所以字符串不是垃圾回收。
答案 3 :(得分:2)
String
对象是不可变的,但Foo
对象不是。 myfoobar.m_foo
和myfoo
指向同一个对象,因此共享a
成员。
答案 4 :(得分:1)
您可能习惯了变量和对象在C ++中的工作方式。
非原始类型的变量总是引用到Java中的对象,与C ++不同,其中变量代表对象本身。
Java中的对象始终在堆上分配。对象永远不会在堆栈*上作为“临时变量”,就像在C ++中一样。
*:实际上,JVM可能会做一些优化并将对象放在堆栈上,但这与理解变量和对象在Java中的工作方式无关。
答案 5 :(得分:0)
由于Java也按值传递对象引用。现在,这里变得棘手:
public void tricky(Point arg1,Point arg2)
{
arg1.x = 100;
arg1.y = 100;
Point temp = arg1;
arg1 = arg2;
arg2 = temp;
}
public static void main(String [] args)
{
点pnt1 =新点(0,0);
点pnt2 =新点(0,0);
System.out.println(“X:”+ pnt1.x +“Y:”+ pnt1.y);
System.out.println(“X:”+ pnt2.x +“Y:”+ pnt2.y);
System.out.println(“”);
棘手(PNT1,PNT2);
System.out.println(“X:”+ pnt1.x +“Y:”+ pnt1.y);
System.out.println(“X:”+ pnt2.x +“Y:”+ pnt2.y);
}
**如果我们执行这个main()方法,我们会看到以下输出:
X:0 Y:0
X:0 Y:0
X:100 Y:100
X:0 Y:0 **