I was going through this excellent article on Java reference semantics
by Jon Skeet
, where he states that
We assume the presence of a procedure named f that takes a formal parameter s. We call that function giving it an actual parameter g.
The calling code:
f( g )
The function:
procedure f( s ) begin -- body of the procedure end;
All object instances in Java are allocated on the heap and can only be accessed through object references. So if I have the following:
StringBuffer g = new StringBuffer( "Hello" );
The variable g does not contain the string "Hello", it contains a reference (or pointer) to an object instance that contains the string "Hello".
So if I then call f( g ), f is free to modify its formal parameter s to make it point to another StringBuffer or to set it to null. The function f could also modify the StringBuffer by appending " World" for instance. While this changes the value of that StringBuffer, the value of that StringBuffer is NOT the value of the actual parameter g.
my understanding could be wrong. the program below does change the Stringbuffer passed to the method
public class MutabilityStringBuffer {
public static void main(String[] args){
StringBuffer sb = new StringBuffer("hello");
System.out.println("String before append: "+ sb.toString());
addString(sb);
System.out.println("Sting after append "+ sb.toString());
String s = "hello";
System.out.println("String before append: "+ s);
addString(s);
System.out.println("Sting after append "+ s);
}
public static void addString(StringBuffer word){
word.append(" world!");
}
public static void addString(String word){
word+=" world!";
}
}
ofcourse, Jon Skeet could not be wrong. But I see that the Stringbuffer
can be changed by passing it to method, because stringbuffer
is mutable, which is a bit contradictory to what Skeet posted. please clear my understanding here.
Thanks
See comments
StringBuffer sb = new StringBuffer("hello"); // sb holds reference
System.out.println("String before append: "+ sb.toString()); // you print the value
addString(sb); // you use the reference to append to the StringBuffer
System.out.println("Sting after append "+ sb.toString()); // you print the value
String s = "hello"; // s holds a refernece
System.out.println("String before append: "+ s); // you print its value
addString(s); // // the word variable would hold a new reference inside the method
System.out.println("Sting after append "+ s); // you print its value
In here
public static void addString(String word){
word+=" world!";
}
The original value of the reference passed to word
changes when you reassign it with
word+=" world!";
It goes something like this
String word = [copy of value of the argument's reference];
word = word.toString() /* toString() is unnecessary, but just to make the point */ + " world";
where the result of String concatenation is a new String object and therefore a new reference.
In the following
public static void addString(StringBuffer word){
word.append(" world!");
}
you access the object referenced by word
, call a method on that object which internally modifies a char[]
. So you've changed the value of the object, not the value of the reference. Changing the reference would look like
public static void addString(StringBuffer word){
word = new StringBuffer("Answer to the Ultimate Question of Life, the Universe, and Everything: ");
word.append("42");
}
The append
is performed on a new StringBuffer
object, not the one you passed as an argument, proof that the objects are passed by value.