Java is always pass-by-value. That means that a copy of the object reference is created for the sb parameter (and the s parameter too). What you are doing in the method is simple setting this copy of the reference to null. Nothing "gets back" to the caller.
This is confusing because Java seems to sometimes act like pass-by-reference, since you have a copy of the original (caller's) reference to the object, you can make changes to the object that are "seen" by the caller. So when you do the sb.append(str), the caller's object is affected, because the copy of the reference still points to the caller's object.
All things are lawful, but not all things are profitable.
The reason is that Java passes parameters by value, not by reference. In the code above you have to references to the same StringBuilder (one in the main method, and one in the testRefs method). When you assign a value to a reference it only affects that reference, and any other references are left unchanged.
You may be getting confused in this example because both references happen to have the same name. If I re-write the code and change the names it may make it more clear.
So as you can see now, the StringBuilder reference in the main method is not the same StringBuilder reference in the testRef method.
When you call the testRef method, the value of sb is copied into localParameter. The value that is copied is effectively a pointer to the StringBuilder object. This means that both references end up pointing at the same object (so when you call methods on that object in testRef the effect of those calls can be seen in the main method). However assigning the value of null to localParameter only affects localParameter and leaves sb unchanged.
All references are mutable if they are not final. However if you mean are instances of the StringBuilder class mutable, then yes they are (or they wouldn't be much use as builders).
But something being mutable doesn't mean it stays the same, it means it can be changed. And it doesn't have anything to do with why setting the local parameter to null in testRef has no affect on the (different) local parameter in the main method.
Joe McTigue wrote:So if sb is only a local reference, then why does the following substituted for 'sb = null' affect the original value of sb and the previous 'sb = null' did not?
replace "sb = null" in previous code with:
There is only one StringBuilder object (created in the main method). Both of the StringBuilder references are pointing to the same object. Imagine the object as a balloon, and the references are strings attached to the balloon. When you call the testRef method you copy sb into the parameter. This is like attaching a second string to the balloon.
When you set the local parameter in testRef to null that is like you cut the string with some scissors. That parameter in the method is no longer pointing to the object, but the other reference is left unaffected. This does not affect the internal state of the object, it just changes the value of the reference. But when you call the method on the object you are affecting the internal state of the StringBuilder object. This change can be seen from any references that you have attached to it.