问题
I do not understand why System.out.println(name) outputs Sam without being affected by the method's concat function, while System.out.println(names) outputs Sam4 as a result of the method's append method. Why is StringBuilder affected and not String? Normally, calling methods on a reference to an object affects the caller, so I do not understand why the String result remains unchanged. Thanks in advance
public static String speak(String name) {
name = name.concat("4");
return name;
}
public static StringBuilder test(StringBuilder names) {
names = names.append("4");
return names;
}
public static void main(String[] args) {
String name = "Sam";
speak(name);
System.out.println(name); //Sam
StringBuilder names = new StringBuilder("Sam");
test(names);
System.out.println(names); //Sam4
}
回答1:
Because when you call speak(name);
, inside speak when you do
name = name.concat("4");
it creates a new object because String
s are immutable. When you change the original string it creates a new object,I agree that you are returning it but you are not catching it.
So essentially what you are doing is :
name(new) = name(original) + '4'; // but you should notice that both the names are different objects.
try
String name = "Sam";
name = speak(name);
Of course now I think there is no need to explain why it's working with StringBuilder
unless if you don't know that StringBuilder
is mutable.
回答2:
Looking at the Javadoc for String, one will read that
[...] String objects are immutable [...].
This means concat(String) does not change the String
itself, but constructs a new String
.
StringBuilders, on the other hand, are mutable. By calling append(CharSequence), the object itself is mutated.
回答3:
Because String
is immutable and hence String#concat
does not modify the original String instance, it only returns a new String
while the original is left unmodified, while StringBuilder
is mutable and the change is reflected in the StringBuilder
instance passed as parameter.
回答4:
Okay, what is speak
method doing?
First of all,
name.concat("4");
creates new object, which is equal to name
, concatenated with "4"
.
So, the line
name = name.concat(4);
redefines local (for speak
method) variable name
.
Then you return the reference to this new value with
return name;
So, the original variable, passed within method is not modified, but the method returns modified value.
In the test
method you actually modify variable without modifying the reference (the StringBuilder
class is mutable, so variable if this type can be modified).
Then we can see another question arising: why StringBuilder.append
returns value, where it can seem redundant. The answer to this question lies in the description of "builder" pattern, for which it is the usual way of implementing modification methods. See wikipedia on Builder pattern.
回答5:
String
is immutable in java. As soon as you invoke concat
method on name. A new string is created and while you are playing with the old reference in System.out.println(name)
.If you want to use the modified string you should explicitly return the reference.
While StringBuilder
is mutable and it returns the same reference always.
回答6:
When you invoke speak(name)
it computes the new value, but discards it.
If you replace it with
name = speak(name);
the result will be the one you expect.
With the StringBuilder
, the object you pass is mutable: so
names.append(names);
changes the state of the current object (it also returns a reference to the same object, which is just a convenience to allow you to write code like names.append(...).append(...)
etc.). So in the case of the StringBuilder
, the object you are referencing when you call the method has actually changed, hence you see the changes.
回答7:
In your method speak
, the concat method returns a new String, the original object it was called on is unchanged (strings are immutable). As documented:
If the length of the argument string is
0
, then thisString
object is returned. Otherwise, aString
object is returned that represents a character sequence that is the concatenation of the character sequence represented by thisString
object and the character sequence represented by the argument string.
Calling name.concat("4")
is the equivalent of name + "4"
.
In your test
method the append method modifies the content of the StringBuilder
. As documented:
The principal operations on a
StringBuilder
are theappend
andinsert
methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string builder. Theappend
method always adds these characters at the end of the builder; theinsert
method adds the characters at a specified point.
In your main method both name
and names
are still the same object as before the method call, but the content of name
is unchanged as strings are immutable, while the content of names
has been changed.
If instead you had used the return values of both methods, then you would have the result you were expecting.
回答8:
First of all, String
is an immutable class in Java. An immutable class is simply a class whose instances cannot be modified. All information in an instance is initialized when the instance is created and the information can not be modified.
Second, in java parameters are sent by values and not by reference.
In your method 'test' you don't need names = names.append("4")
, instead names.append("4")
will be enough .
If you check java docs for String object, you will see that most of the methods there, including concat, will generate a new String.
So to have on output Sam4 also for the String, you will need in main method to have this name = speak(name)
.
回答9:
String
String is immutable ( once created can not be changed )object . The object created as a String is stored in the Constant String Pool . Every immutable object in Java is thread safe ,that implies String is also thread safe . String can not be used by two threads simultaneously. String once assigned can not be changed.
String demo = " hello " ; // The above object is stored in constant string pool and its value can not be modified.
demo="Bye" ; //new "Bye" string is created in constant pool and referenced by the demo variable // "hello" string still exists in string constant pool and its value is not overrided but we lost reference to the "hello"string
StringBuilder
StringBuilder is same as the StringBuffer , that is it stores the object in heap and it can also be modified . The main difference between the StringBuffer and StringBuilder is that StringBuilder is also not thread safe. StringBuilder is fast as it is not thread safe .
For more details check this
Conclusion:
You don't need to re-assign the value again to StringBuilder
as it is already a reference
test method should be
public static void test(StringBuilder names) {
names.append("4");
}
but speak should be
String name = "Sam";
name = speak(name);
来源:https://stackoverflow.com/questions/31382825/pass-by-value-stringbuilder-vs-string