Java按值传递--您能解释一下吗?

Java按值传递--您能解释一下吗?,java,reference,Java,Reference,我读过,这是有道理的:Java严格按值传递;当对象是参数时,对象的引用按值传递 然而,我完全不明白为什么下面的代码片段可能会起作用。 Foo有一个字符串成员变量a,该变量是不可变的,每次都需要在其中刻录。 第一种燃烧方法(注释掉)应该可以很好地工作,而且确实如此。 第二个方法集的a对传递的值的引用。如果newstr是一个临时变量,则它不应该工作。预期的产出结果是: Totally temp NULL 然而,我明白了 Totally temp Totally temp 为什么??临时变量引用仍

我读过,这是有道理的:Java严格按值传递;当对象是参数时,对象的引用按值传递

然而,我完全不明白为什么下面的代码片段可能会起作用。
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/*这不应该起作用:*/
不应该起作用吗?也许,如果你解释你的想法,我们可以用更好的方式解释为什么会这样;谢谢大家把这件事弄清楚。第一个是把不可变对象看作成员变量,比如字符串。成员变量实际上是对字符串的引用。我“知道”,但现在我真的明白了。第二件事是垃圾收集。如果将对局部变量的引用保存到其他地方,则当它超出范围时,不会删除该局部变量。