I read this excellent article and it make sense: Java is strictly pass by value; when an object is a parameter, the object's reference is passed by value.
However, I'm totally confused as to why the following snippet could possibly work.
Foo
has a String member variable a
which is immutable and needs to be burned in every time.
The first method of burning (commented out) should work fine and it does.
The second method set's a
's reference to the value that was passed. It should not work if newstr
is a temporary variable. The expected output results are:
Totally temp
NULL
However, I get
Totally temp
Totally temp
Why? Is it just pure luck that the temporary variable reference is still good?
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(){};
pu开发者_运维百科blic 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 has a String member variable a which is immutable and needs to be burned in every time.
No it doesn't: it's not marked as final
:
public class Foo {
String a;
...
}
The variable is perfectly mutable - you can change it to refer to a different string at any time, which is what you do in the burna
method.
I don't currently see why you think this wouldn't work:
public void burna(String newstr){
a = newstr; /*this should not work: */
}
That's setting the value of a
to be the value of newstr
- which is a reference to a string (or null). That's all it's doing. I'm not sure what you mean by "burning in" a variable though.
You're calling burna
and passing in a reference to a string with the text "Totally temp\n" - so a
is set to a reference to that string.
What do you mean by "It should not work if newstr
is a temporary variable." There's no such thing as a "temporary variable". There's a local variable - but an object isn't destroyed just because a variable which refers to it goes out of scope. Is that what's confusing you?
Your program has several things going on - the foobar
class probably isn't helping you in terms of understanding. Could you try to simplify your code to the point where it's still confusing you, but there's less going on? Then we could isolate the source of confusion more precisely.
The problem appears to be that you don't understand how garbage collection works. As long as at least one reference to an object remains valid, that object will not be collected.
There are two references to the string "Totally temp\n". One is temp
the other is a
in the Foo
object. At the end of dofoo
temp
goes out of scope, so that's one reference less. However you still have the other reference, so the string is not garbage collected.
The String
object is immutable, but the Foo
object is not. myfoobar.m_foo
and myfoo
point to the same object and thus share the a
member.
You might be used to the way variables and objects work in C++.
Variables of non-primitive types are always references to objects in Java, unlike in C++, where variables represent objects themselves.
Objects in Java are always allocated on the heap. Objects are never on the stack* as "temporary variables", like in C++.
*: actually, the JVM might do some optimizations and put objects on the stack, but that's not relevant for understanding the concept of how variables and objects work in Java.
Since Java passes object references by value as well. Now, here is where it gets tricky:
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)
{
Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);
System.out.println("X: " + pnt1.x + " Y: " +pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
System.out.println(" ");
tricky(pnt1,pnt2);
System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
}
**If we execute this main() method, we see the following output:
X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0**
精彩评论