In many texts String is cited as the 'gold standard' of Java's various immutable classes. Any google of 'Immutable Java' will invariably reveal examples using String to demonstrate the benefits and characteristics of a good immutable class.
From Wikipedia(http://en.wikipedia.org/wiki/Immutable_object) we get the following definition:-
'In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created.'
I like this definition as it describes what I had assumed to be the main point: that an instance's state should not be allowed to be modified post-construction.
However, I recently found myself looking at the String class and came across its hashCode() method :-
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
Looking closely we see that this is a classic implementation of the 'lazy evaluation' pattern. Rather than computing the hash value in the constructor, or computing it each time the hashCode() method is called,we compute it once (on the first call to hashCode()) and save the computed value in the hash field.
We can see this if we read the private hash field reflectively.
String helloWorld = "helloWorld";
Field field=String.class.getDeclaredField("hash");
field.setAccessible(true); // because hash field is private
System.out.println("Before first hashcode call "+field.getInt(helloWorld));
helloWorld.hashCode();
System.out.println("After first hashcode call "+field.getInt(helloWorld));
If one runs this snippet of code it will output something like
Before first hashcode call 0
After first hashcode call -1554135584
So for a String instance which we create, but for which we never call hashCode(), the private hash field will remain 0. It is only changed when we call hashCode().
By Wikipedia's definition I believe String fails the immutablility test.
The argument might be that we can't observe a String instance in a different state without resorting to a reflective read of String's hash field and because the call to retrieve the state actually modifies it; if we can't observe it changing, then it didn't change.
This is reminiscent of
"If a tree falls in a forest and nobody hears it, did it make a noise?"
Or my personal version
"If I say something in a room and my wife doesn't hear me, am I still wrong?"
However it still seems like String is not immutable.
In Eric Lippert's blog (http://blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx) he refers to this as 'Popsicle Immutability' and although it seems safe, (ignoring reflective access) it does seem incorrect.
So I would like to open up a discussion: Is String immutable?
-------------------------
The information presented in this document is for informational purposes only and may contain technical inaccuracies, omissions and typographical errors. Links to third party sites are for convenience only, and no endorsement is implied