java.lang.String is NOT immutable
I found some code on a Java mailing list that challenges a lot of the assumptions about how strings work in Java.
There is a standard newbie question about immutable strings. It goes like this:
What gets printed out:
String lc = "lowercase"; lc.toUpperCase(); System.out.println(lc);
The standard answer is that you get "lowercase" because in Java, strings are immutable. The standard answer goes on to explain the benefits to security of having immutable strings, and how values can't be changed after they've been checked. I'm sure you've seen it all before.
So what about the following code:
String lc = "lowercase"; Mutant.toUpperCase(lc); System.out.println(lc);
You'd think that because Mutant wasn't even part of the String class that it couldn't alter lc, but Mutant.toUpperCase(lc); uses a simple reflection trick to edit the string:
public static void toUpperCase(String orig)
{
try
{
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(orig, orig.toUpperCase().toCharArray());
}
catch (Exception ex)
{
}
}
The original article goes into a lot more depth, and a follow-up shows how to change the values of Integers too!.
The solution to the problem is to run your code with a Security manager turned on. That way you can be sure that people are not messing about with private variables.
Re: java.lang.String is NOT immutable
Re: java.lang.String is NOT immutable
Your point rests on an assumption that some would argue with: that String is effectively a 'primitive' like int or float, which are clearly intended to be 'value types'. But is it?
I don't feel strongly one way or the other, but just to play Devi's advocate...
If String were intended to be purely a 'value type' than the language designers (Gosling and Co.) should have made it a primitive. But it isn't. It's an object. Why make it an object and then make it immutable?
This made the usage of String an unnecessary exception to standard object semantics--an exception that everyone has to learn to deal with (usually the hard way). I call it 'unnecessary' because, as far as I can determine, there was no clear benefit to making it an object that would offset the drawbacks. IMNSHO, this was a language design mistake.
Others would take a different tack and argue that including primitives in Java was the real design mistake. There is a case to be made for avoiding primitives and making *everything* in the language an object. I don't have a firm opinion on that either way, but it is an interesting argument.