可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
Is Java “pass-by-reference” or “pass-by-value”?
76 answers
public class StackOverFlow {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("A");
al.add("B");
markAsNull(al);
System.out.println("ArrayList elements are "+al);
String str = "Hello";
markStringAsNull(str);
System.out.println("str "+ str);
}
private static void markAsNull(ArrayList<String> str){
str.add("C");
str= null;
}
private static void markStringAsNull(String str){
str = str + "Append me";
str = null;
}
}
This outputs:
ArrayList elements are [A, B, C]
str Hello
In the case of ArrayList
, the added elements are getting retrieved.
In case of String
the method call has no effect on the String being passed. What exactly is the JVM doing? Can anyone explain in detail?
回答1:
In the case of Arraylist string objects the added elements are getting retrived. In case of String the method call has no effect on the String being passed.
It happens cause Java is Pass-by-Value and String
s are immutable
When you call
markAsNull(ArrayList<String> str)
The a new reference by name str
is created for the same ArrayList
pointed by al
. When you add
an element on str
it gets added to same object. Later you put str
to null
but the object has the new values added and is pointed by a1
.
When you call
markStringAsNull(String str)
{
str = str + "Append me";
// ...
}
The line str = str + "Append me";
creates a new String
object by appending the given string and assignes it to str
. but again it is just reference to actual string which now pointing to newly created string. (due to immutablity) and the original string is not changed.
回答2:
The markXAsNull
methods are setting the local references to be null
. This has no effect on the actual value stored at that location. The main
method still has its own references to the values, and can call println
using those.
Also, when doing the string concatenation, toString()
is being called on the Object, and that is why the ArrayList is outputted as a list of its values in brackets.
回答3:
Java follows passby value concept ( there is no pass by reference in java ) . So when you pass a string to the function it sends a "copy of reference" to that string to the function. So even if you set the variable to null in the function, when it returns to the caller it refers its original value only. That's why original string has no effect.
In case of Arraylist, copy of reference refers to the original Arraylist (which is also the same in case of string). But when you add something into ArrayList, it refers to the original object and so that you can see the effect. ( try in method arraylist=new ArrayList(), your original arraylist will remain as it is).
In case of string, when you do
str=str + "abc";
Java creates a new String object which will have reference to string "xyzabc" ( e.g. str="xyz") and "xyz" will be eligible for the garbage collection. But as "xyz" is still having an variable which refers to it it ( original string) will not be garbage collected. But as soon as the function call gets over "xyzabc" goes for garbage collection.
Summary of the discussion is, as long as an reference refers to the same object you can make changes in the function, but when you try to change the reference ( str=str+"abc") you are refering to the new object in the method so that your original object will remain as it is.
回答4:
From the Book: SCJP - Sun Certified Programmer for Java 6 Study Guide (Katty Sierra - Bert Bates) Chapter 3 Objective 7.3 - Passing Variables Into Methods
Java is actually pass-by-value for all variables running within a single
VM. Pass-by-value means pass-by-variable-value. And that means, pass-by-copy-ofthe-
variable!
The bottom line on pass-by-value: the called method can't change the caller's
variable, although for object reference variables, the called method can change the
object the variable referred to. What's the difference between changing the variable
and changing the object? For object references, it means the called method can't
reassign the caller's original reference variable and make it refer to a different object,
or null. For example, in the following code fragment,
void bar() {
Foo f = new Foo();
doStuff(f);
}
void doStuff(Foo g) {
g.setName("Boo");
g = new Foo();
}
reassigning g does not reassign f! At the end of the bar() method, two Foo objects
have been created, one referenced by the local variable f and one referenced by
the local (argument) variable g. Because the doStuff() method has a copy of the
reference variable, it has a way to get to the original Foo object, for instance to call
the setName() method. But, the doStuff() method does not have a way to get to
the f reference variable. So doStuff() can change values within the object f refers
to, but doStuff() can't change the actual contents (bit pattern) of f. In other
words, doStuff() can change the state of the object that f refers to, but it can't
make f refer to a different object!
回答5:
In Java, you may create one object, and referenced by multiple pointers. Calling a mutator method on any pointer will effectively modify the sole object, thus updating all other references.
But if you call variable assignment statements on a reference, only that pointer will be changed, since it doesn't do any object side work (this is the best I could explain...).
Passing an object to a parameter will effectively copy the reference, resulting in a single object, with two pointers - one global, and the other local.
One more point, since String
is immutable, you'll actually get a new object, that is distinct from the original (from the fact that you have to say a = a + "a"
), that's why it won't modify the original string.