Java按值传递--您能解释一下吗?
我读过,这是有道理的:Java严格按值传递;当对象是参数时,对象的引用按值传递 然而,我完全不明白为什么下面的代码片段可能会起作用。Java按值传递--您能解释一下吗?,java,reference,Java,Reference,我读过,这是有道理的:Java严格按值传递;当对象是参数时,对象的引用按值传递 然而,我完全不明白为什么下面的代码片段可能会起作用。 Foo有一个字符串成员变量a,该变量是不可变的,每次都需要在其中刻录。 第一种燃烧方法(注释掉)应该可以很好地工作,而且确实如此。 第二个方法集的a对传递的值的引用。如果newstr是一个临时变量,则它不应该工作。预期的产出结果是: Totally temp NULL 然而,我明白了 Totally temp Totally temp 为什么??临时变量引用仍
Foo
有一个字符串成员变量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);
}
Foo有一个字符串成员变量a,该变量是不可变的,每次都需要刻录
不,它没有:它没有被标记为最终版
:
public class Foo {
String a;
...
}
变量是完全可变的-您可以随时更改它以引用不同的字符串,这就是您在burna
方法中所做的
我现在不明白你为什么认为这不管用:
public void burna(String newstr){
a = newstr; /*this should not work: */
}
这是将a
的值设置为newstr
的值,这是对字符串(或null)的引用。这就是它所做的一切。我不知道你说的“烧入”变量是什么意思
您正在调用burna
并传入对一个字符串的引用,该字符串的文本为“tolly temp\n”-因此a
被设置为对该字符串的引用
你所说的“如果
newstr
是一个临时变量,那么它就不应该起作用”是什么意思。有一个局部变量,但对象不会因为引用它的变量超出范围而被销毁。这就是让你困惑的原因吗
你的程序有几个方面在进行中,
foobar
类可能对你的理解没有帮助。您是否可以尝试将代码简化到仍然让您感到困惑的程度,但这样做的情况会更少?然后,我们可以更精确地隔离混淆的来源。有两个字符串“total temp\n”的引用。一个是temp
另一个是Foo
对象中的a
。在dofoo
temp
的末尾,这超出了范围,因此少了一个参考。但是,您仍然有另一个引用,因此字符串不会被垃圾收集。字符串对象是不可变的,但是Foo
对象不是myfoobar.m_foo
和myfoo
指向同一个对象,因此共享a
成员。问题似乎在于您不了解垃圾收集是如何工作的。只要至少一个对象的引用保持有效,该对象就不会被收集。 < P>您可能会习惯于变量和对象在C++中的工作方式。
<> >非原始类型的变量总是引用java中的对象,不同于C++,变量在这里表示对象本身。
Java中的对象总是在堆上分配。对象从不堆栈*作为“临时变量”,如C++中。
*:实际上,JVM可能会进行一些优化并将对象放在堆栈上,但这与理解Java中变量和对象如何工作的概念无关。,因为Java也通过值传递对象引用。现在,这里是它变得棘手的地方: 公共空间(arg1点、arg2点) { arg1.x=100 arg1.y=100 点温度=arg1 arg1=arg2 arg2=温度 } 公共静态void main(字符串[]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**…a=newstr表示(字符串是对象)“将a设置为引用与newstr引用的对象相同的对象”。@Will a:我更喜欢将它们视为恰好是引用的值。这与原语类型更加一致,赋值只是将值从RHS复制到LHS上的变量。很好,很简单。完全同意-一切都是按值传递的,非常简单。“一个对象不会因为引用它的变量超出范围而被销毁。这就是让你困惑的地方吗?”是的!因此,如果我创建一个局部变量并将其引用存储在其他地方(如本例中),它将不会被垃圾收集。。。直到myfoobar被垃圾回收(在本例中)?才尝试过清空myfoobar,而foo的字符串仍然是安全的。所以我猜它不会被垃圾收集(当然,除非myfoo走了)。对吗?
String
对象是不可变的,但是Foo
对象不是myfoobar.m_foo
和myfoo
指向同一个对象,因此共享a
成员。您所说的“烧掉”是什么意思?另外,您为什么认为a=newstr/*这不应该起作用:*/
不应该起作用吗?也许,如果你解释你的想法,我们可以用更好的方式解释为什么会这样;谢谢大家把这件事弄清楚。第一个是把不可变对象看作成员变量,比如字符串。成员变量实际上是对字符串的引用。我“知道”,但现在我真的明白了。第二件事是垃圾收集。如果将对局部变量的引用保存到其他地方,则当它超出范围时,不会删除该局部变量。