So I’m preparing for the Sun Certified Java Programmer for Java 6 course (now Oracle Certified Professional or something like that, I think, but the book still calls it SCJP).
And I come across this lovely bit in chapter 3:
One exception to the way object references are assigned is String. In Java, String objects are given special treatment. For one thing, String objects are immutable; you can't change the value of a String object […]. But it sure looks as though you can. Examine the following code:[…] String x = "Java"; // Assign a value to x […] x = x + " Bean"; // Now modify the object using // the x reference
For any other object type, where two references refer to the same object, if either reference is used to modify the object, both references will see the change because there is still only a single object. But any time we make any changes at all to a String, the VM will update the reference variable to refer to a different object. […]
You need to understand what happens when you use a String reference variable to modify a string:
- A new string is created (or a matching String is found in the String pool), leaving the original String object untouched.
- The reference used to modify the String (or rather, make a new String by modifying a copy of the original) is then assigned the brand new String object.
So when you say1. String s = "Fred"; 2. String t = s; // Now t and s refer to the same // String object 3. t.toUpperCase(); // Invoke a Strong method that changes // the String
you haven't changed the original String object created on line 1. When line 2 completes, both
sreference the same String object. But when line 3 runs, rather than modifying the object referred to by
t(which is the one and only String object up to this point), a brand new String object is created. And then abandoned. […]
(Emphasis in the original.)
Which contains a bunch of lies. (Not all of it, but too much of it.)
As best as I can see, String objects aren’t special in this particular respect; the same is true of other immutable classes.
It all boils down to the fact that you can’t modify String objects. If you want to change the value, you get a new String object, whether this is because you applied an operator (
s + " Bean") or called a method on it (
t.toUpperCase()). Assigning this new object to a variable, uh, assigns this new object to the variable. Same behaviour as when you assign any new object to a reference variable: other variables that reference the object that the variable used to point to continue to refer to the previous object.
It’s exactly the same with, say, java.math.BigDecimal, which is also not mutable and which returns new objects if you try to do arithmetic. For example, in
BigDecimal first = new BigDecimal("17"); BigDecimal copy = first; BigDecimal second = new BigDecimal("21"); first = first.add(second);, the “add” method will return a new BigDecimal object. If you turn around and assign it straight back to the variable “first”, then that doesn’t change the BigDecimal object that had the value 17; that one is still around and still pointed to by the variable “copy”; it’s just not pointed to by the variable “first” any more.
s = s + " Bean"; is not any more special than
s = "C#";; in both cases, we point the variable to a new String object. There’s no “mak[ing] any changes […] to a String” or “changes the String” of any kind going on anywhere, nor any “special treatment” of String objects that I can see.